SCIP Doxygen Documentation
Loading...
Searching...
No Matches
cuts.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 cuts.c
26 * @ingroup OTHER_CFILES
27 * @brief methods for aggregation of rows
28 * @author Jakob Witzig
29 * @author Leona Gottwald
30 * @author Marc Pfetsch
31 */
32
33/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35#include "scip/cuts.h"
36#include "scip/certificate.h"
37#include "scip/dbldblarith.h"
38#include "scip/intervalarith.h"
39#include "scip/lp.h"
40#include "scip/misc.h"
41#include "scip/pub_lp.h"
42#include "scip/pub_lpexact.h"
43#include "scip/pub_message.h"
44#include "scip/pub_misc.h"
46#include "scip/pub_misc_sort.h"
47#include "scip/pub_var.h"
49#include "scip/scip_cut.h"
50#include "scip/scip_exact.h"
51#include "scip/scip_lp.h"
52#include "scip/scip_mem.h"
53#include "scip/scip_message.h"
54#include "scip/scip_numerics.h"
55#include "scip/scip_prob.h"
56#include "scip/scip_sol.h"
58#include "scip/scip_var.h"
59#include "scip/struct_lp.h"
60#include "scip/struct_lpexact.h"
61#include "scip/struct_scip.h"
62#include "scip/struct_set.h"
65#include "scip/rational.h"
66
67/*
68 * Default values for cut generation parameters
69 */
70#define DEFAULT_CUTGEN_POSTPROCESS TRUE /**< default for applying post-processing */
71#define DEFAULT_CUTGEN_BOUNDSWITCH 0.5 /**< default fraction of domain for bound switching */
72#define DEFAULT_CUTGEN_ALLOWLOCAL TRUE /**< default for allowing local cuts */
73#define DEFAULT_CUTGEN_VARTYPEUSEVBDS 2 /**< default variable types for varbound substitution */
74#define DEFAULT_CUTGEN_MINFRAC 0.05 /**< default minimal fractionality of rhs */
75#define DEFAULT_CUTGEN_MAXFRAC 0.999 /**< default maximal fractionality of rhs */
76#define DEFAULT_CUTGEN_MAXTESTDELTA (-1) /**< default maximum number of deltas to test (-1 = unlimited) */
77
78/* =========================================== general static functions =========================================== */
79#ifdef SCIP_DEBUG
80static
81void printCutQuad(
82 SCIP* scip, /**< SCIP data structure */
83 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
84 SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
85 QUAD(SCIP_Real cutrhs), /**< right hand side of the MIR row */
86 int* cutinds, /**< indices of problem variables for non-zero coefficients */
87 int cutnnz, /**< number of non-zeros in cut */
88 SCIP_Bool ignoresol,
89 SCIP_Bool islocal
90 )
91{
92 SCIP_Real QUAD(activity);
93 SCIP_VAR** vars;
94
95 assert(scip != NULL);
97
98 SCIPdebugMsg(scip, "CUT:");
99 QUAD_ASSIGN(activity, 0.0);
100
101 /**! [SnippetCodeStyleInLoopDeclaration] */
102 for( int i = 0; i < cutnnz; ++i )
103 {
104 SCIP_Real QUAD(coef);
105
106 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
107
108 if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_BINARY )
109 SCIPdebugMsgPrint(scip, " %+g<%s>[B]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
110 else if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_INTEGER )
111 SCIPdebugMsgPrint(scip, " %+g<%s>[I]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
112 else
113 SCIPdebugMsgPrint(scip, " %+g<%s>[C]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
114
115 if( ! ignoresol )
116 {
117 SCIPquadprecProdQD(coef, coef, (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]])));
118 }
119 else
120 {
121 if( cutcoefs[i] > 0.0 )
122 {
123 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]])));
124 }
125 else
126 {
127 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]])));
128 }
129 }
130
131 SCIPquadprecSumQQ(activity, activity, coef);
132 }
133 /**! [SnippetCodeStyleInLoopDeclaration] */
134 SCIPdebugMsgPrint(scip, " <= %.6f (activity: %g)\n", QUAD_TO_DBL(cutrhs), QUAD_TO_DBL(activity));
135}
136
137static
138void printCut(
139 SCIP* scip, /**< SCIP data structure */
140 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
141 SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
142 SCIP_Real cutrhs, /**< right hand side of the MIR row */
143 int* cutinds, /**< indices of problem variables for non-zero coefficients */
144 int cutnnz, /**< number of non-zeros in cut */
145 SCIP_Bool ignoresol,
146 SCIP_Bool islocal
147 )
148{
149 SCIP_Real activity;
150 SCIP_VAR** vars;
151 int i;
152
153 assert(scip != NULL);
155
156 SCIPdebugMsg(scip, "CUT:");
157 activity = 0.0;
158 for( i = 0; i < cutnnz; ++i )
159 {
160 SCIP_Real coef;
161
162 coef = cutcoefs[cutinds[i]];
163
164 if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_BINARY )
165 SCIPdebugMsgPrint(scip, " %+g<%s>[B]", coef, SCIPvarGetName(vars[cutinds[i]]));
166 else if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_INTEGER )
167 SCIPdebugMsgPrint(scip, " %+g<%s>[I]", coef, SCIPvarGetName(vars[cutinds[i]]));
168 else
169 SCIPdebugMsgPrint(scip, " %+g<%s>[C]", coef, SCIPvarGetName(vars[cutinds[i]]));
170
171 if( ! ignoresol )
172 {
173 coef = coef * (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]]));
174 }
175 else
176 {
177 if( cutcoefs[i] > 0.0 )
178 {
179 coef = coef * (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]));
180 }
181 else
182 {
183 coef = coef * (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
184 }
185 }
186
187 activity += coef;
188 }
189 SCIPdebugMsgPrint(scip, " <= %.6f (activity: %g)\n", cutrhs, activity);
190}
191#endif
192
193/** macro to make sure a value is not equal to zero, i.e. NONZERO(x) != 0.0
194 * will be TRUE for every x including 0.0
195 *
196 * To avoid branches it will add 1e-100 with the same sign as x to x which will
197 * be rounded away for any sane non-zero value but will make sure the value is
198 * never exactly 0.0.
199 */
200#define NONZERO(x) (COPYSIGN(1e-100, (x)) + (x))
201
202/** add a scaled row to a dense vector indexed over the problem variables and keep the
203 * index of non-zeros up-to-date
204 */
205static
207 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
208 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
209 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
210 SCIP_ROW* row, /**< row coefficients to add to variable vector */
211 SCIP_Real scale /**< scale for adding given row to variable vector */
212 )
213{
214 int i;
215
216 assert(inds != NULL);
217 assert(vals != NULL);
218 assert(nnz != NULL);
219 assert(row != NULL);
220
221 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
222 for( i = 0 ; i < row->len; ++i )
223 {
224 SCIP_Real val;
225 int probindex;
226
227 probindex = row->cols[i]->var_probindex;
228 val = vals[probindex];
229
230 if( val == 0.0 )
231 inds[(*nnz)++] = probindex;
232
233 val += row->vals[i] * scale;
234
235 /* the value must not be exactly zero due to sparsity pattern */
236 val = NONZERO(val);
237
238 assert(val != 0.0);
239 vals[probindex] = val;
240 }
241
242 return SCIP_OKAY;
243}
244
245/** add a scaled row to a dense vector indexed over the problem variables and keep the
246 * index of non-zeros up-to-date
247 *
248 * This is the quad precision version of varVecAddScaledRowCoefs().
249 */
250static
252 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
253 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
254 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
255 SCIP_ROW* row, /**< row coefficients to add to variable vector */
256 SCIP_Real scale /**< scale for adding given row to variable vector */
257 )
258{
259 int i;
260
261 assert(inds != NULL);
262 assert(vals != NULL);
263 assert(nnz != NULL);
264 assert(row != NULL);
265
266 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
267 for( i = 0 ; i < row->len; ++i )
268 {
269 SCIP_Real QUAD(scaledrowval);
270 SCIP_Real QUAD(val);
271 int probindex;
272
273 probindex = row->cols[i]->var_probindex;
274 QUAD_ARRAY_LOAD(val, vals, probindex);
275
276 if( QUAD_HI(val) == 0.0 )
277 inds[(*nnz)++] = probindex;
278
279 SCIPquadprecProdDD(scaledrowval, row->vals[i], scale);
280 SCIPquadprecSumQQ(val, val, scaledrowval);
281
282 /* the value must not be exactly zero due to sparsity pattern */
283 QUAD_HI(val) = NONZERO(QUAD_HI(val));
284 assert(QUAD_HI(val) != 0.0);
285
286 QUAD_ARRAY_STORE(vals, probindex, val);
287 }
288
289 return SCIP_OKAY;
290}
291
292/** add a scaled row to a dense vector indexed over the problem variables and keep the
293 * index of non-zeros up-to-date
294 *
295 * This is the quad precision version of varVecAddScaledRowCoefs() with a quad precision scaling factor.
296 */
297static
299 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
300 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
301 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
302 SCIP_ROW* row, /**< row coefficients to add to variable vector */
303 QUAD(SCIP_Real scale) /**< scale for adding given row to variable vector */
304 )
305{
306 int i;
307
308 assert(inds != NULL);
309 assert(vals != NULL);
310 assert(nnz != NULL);
311 assert(row != NULL);
312
313 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
314 for( i = 0 ; i < row->len; ++i )
315 {
316 SCIP_Real QUAD(val);
317 SCIP_Real QUAD(rowval);
318 int probindex;
319
320 probindex = row->cols[i]->var_probindex;
321 QUAD_ARRAY_LOAD(val, vals, probindex);
322
323 if( QUAD_HI(val) == 0.0 )
324 {
325 inds[(*nnz)++] = probindex;
326 SCIPquadprecProdQD(val, scale, row->vals[i]);
327 }
328 else
329 {
330 SCIPquadprecProdQD(rowval, scale, row->vals[i]);
331 SCIPquadprecSumQQ(val, val, rowval);
332 }
333
334 /* the value must not be exactly zero due to sparsity pattern */
335 QUAD_HI(val) = NONZERO(QUAD_HI(val));
336 assert(QUAD_HI(val) != 0.0);
337
338 QUAD_ARRAY_STORE(vals, probindex, val);
339 }
340
341 return SCIP_OKAY;
342}
343
344/** add a scaled row to a dense vector indexed over the problem variables and keep the index of non-zeros up-to-date
345 *
346 * In the safe variant, we need to transform all variables (implicitly) to nonnegative variables using their
347 * upper/lower bounds. When adding \f$\lambda * (c^Tx \le d)\f$ to \f$a^Tx \le b\f$, this results in:
348 *
349 * \f{align*}{
350 * m_i & =a_i+\lambda c_i \\
351 * U \cap L & = \emptyset \\
352 * U & = \{ i : x_i \le u_i\} \\
353 * L & = \{ i : x_i \ge l_i\} \\
354 * \sum_{i \in U} \overline{m_i}x_i + \sum_{i \in L}\underline{m_i}x_i
355 * & \le b+ \lambda d + \sum_{i \in U, u_i > 0}(\overline{m_i}-\underline{m_i})u_i + \sum_{i \in L, l_i < 0}(\underline{m_i}-\overline{m_i})l_i
356 * \f}
357 *
358 * This methods sums up the left hand side, and stores the change of the rhs due to the variable bounds in rhschange.
359 *
360 * @note this method is safe for usage in exact solving mode
361 */
362static
364 SCIP* scip, /**< scip data structure */
365 int* inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
366 SCIP_Real* vals, /**< array with values of variable vector */
367 int* nnz, /**< number of non-zeros coefficients of variable vector */
368 SCIP_ROW* row, /**< row coefficients to add to variable vector */
369 SCIP_Real scale, /**< scale for adding given row to variable vector */
370 SCIP_Real* rhschange, /**< change in rhs due to variable conjugation */
371 SCIP_Bool* success /**< was the addition successful? */
372 )
373{
374 int i;
375 SCIP_ROUNDMODE previousroundmode;
376 SCIP_VAR* var;
377 SCIP_ROWEXACT* rowexact;
378
380 assert(inds != NULL);
381 assert(vals != NULL);
382 assert(nnz != NULL);
383 assert(row != NULL);
384 assert(rhschange != NULL);
385 assert(success != NULL);
386 assert(*success);
387
388 previousroundmode = SCIPintervalGetRoundingMode();
390
391 *rhschange = 0;
392 rowexact = SCIProwGetRowExact(row);
393
394 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
395 for( i = 0 ; i < row->len; ++i )
396 {
397 SCIP_Real val;
398 SCIP_INTERVAL valinterval;
399 int probindex;
400
401 probindex = row->cols[i]->var_probindex;
402 var = row->cols[i]->var;
403 val = vals[probindex];
404
405 if( val == 0.0 )
406 {
407 assert(*nnz < SCIPgetNVars(scip));
408 inds[(*nnz)++] = probindex;
409 }
410
411 if( val == SCIP_INVALID ) /*lint !e777*/
412 val = 0.0;
413
414 SCIPintervalSetBounds(&valinterval, rowexact->valsinterval[i].inf, rowexact->valsinterval[i].sup);
415 SCIPintervalMulScalar(SCIPinfinity(scip), &valinterval, valinterval, scale);
416 SCIPintervalAddScalar(SCIPinfinity(scip), &valinterval, valinterval, val);
417
418 if( SCIPisInfinity(scip, REALABS(valinterval.inf)) || SCIPisInfinity(scip, REALABS(valinterval.sup)) )
419 {
420 *success = FALSE;
421 SCIPintervalSetRoundingMode(previousroundmode);
422 return SCIP_OKAY;
423 }
424
426 val = valinterval.inf;
428 val = valinterval.sup;
430 {
431 val = valinterval.inf;
433 *rhschange += (valinterval.sup - valinterval.inf) * (-SCIPvarGetLbGlobal(var));
434 }
436 {
437 val = valinterval.sup;
439 *rhschange += (valinterval.sup - valinterval.inf) * (SCIPvarGetUbGlobal(var));
440 }
441 else
442 {
443 *success = FALSE;
444 SCIPintervalSetRoundingMode(previousroundmode);
445 return SCIP_OKAY;
446 }
447
448 /* we can't set the value to 0 or the sparsity pattern does not work. We can't perturb it slightly because we are solving
449 * exactly; this is taken care of in removeZerosSafely */
450 if( val == 0.0 )
451 val = SCIP_INVALID;
452
453 vals[probindex] = val;
454 }
455
456 SCIPintervalSetRoundingMode(previousroundmode);
457
458 return SCIP_OKAY;
459}
460
461/** calculates the cut efficacy for the given solution */
462static
464 SCIP* scip, /**< SCIP data structure */
465 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
466 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
467 SCIP_Real cutrhs, /**< the right hand side of the cut */
468 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
469 int cutnnz /**< the number of non-zeros in the cut */
470 )
471{
472 SCIP_VAR** vars;
473 SCIP_Real norm = 0.0;
474 SCIP_Real activity = 0.0;
475 int i;
476
477 assert(scip != NULL);
478 assert(cutcoefs != NULL);
479 assert(cutinds != NULL);
480
482
483 switch( scip->set->sepa_efficacynorm )
484 {
485 case 'e':
486 for( i = 0; i < cutnnz; ++i )
487 {
488 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
489 norm += SQR(cutcoefs[i]);
490 }
491 norm = sqrt(norm);
492 break;
493 case 'm':
494 for( i = 0; i < cutnnz; ++i )
495 {
496 SCIP_Real absval;
497
498 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
499 absval = REALABS(cutcoefs[i]);
500 norm = MAX(norm, absval);
501 }
502 break;
503 case 's':
504 for( i = 0; i < cutnnz; ++i )
505 {
506 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
507 norm += REALABS(cutcoefs[i]);
508 }
509 break;
510 case 'd':
511 for( i = 0; i < cutnnz; ++i )
512 {
513 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
514 if( !SCIPisZero(scip, cutcoefs[i]) )
515 norm = 1.0;
516 }
517 break;
518 default:
519 SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", scip->set->sepa_efficacynorm);
520 assert(FALSE); /*lint !e506*/
521 }
522
523 return (activity - cutrhs) / MAX(1e-6, norm);
524}
525
526/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter */
527static
529 SCIP* scip, /**< SCIP data structure */
530 SCIP_Real* vals, /**< array of the non-zero coefficients in the vector; this is a quad precision array! */
531 int* inds, /**< array of the problem indices of variables with a non-zero coefficient in the vector */
532 int nnz /**< the number of non-zeros in the vector */
533 )
534{
535 SCIP_Real norm = 0.0;
536 SCIP_Real QUAD(coef);
537 int i;
538
539 assert(scip != NULL);
540 assert(scip->set != NULL);
541
542 switch( scip->set->sepa_efficacynorm )
543 {
544 case 'e':
545 for( i = 0; i < nnz; ++i )
546 {
547 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
548 norm += SQR(QUAD_TO_DBL(coef));
549 }
550 norm = sqrt(norm);
551 break;
552 case 'm':
553 for( i = 0; i < nnz; ++i )
554 {
555 SCIP_Real absval;
556 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
557
558 absval = REALABS(QUAD_TO_DBL(coef));
559 norm = MAX(norm, absval);
560 }
561 break;
562 case 's':
563 for( i = 0; i < nnz; ++i )
564 {
565 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
566 norm += REALABS(QUAD_TO_DBL(coef));
567 }
568 break;
569 case 'd':
570 for( i = 0; i < nnz; ++i )
571 {
572 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
573 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
574 {
575 norm = 1.0;
576 break;
577 }
578 }
579 break;
580 default:
581 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
582 assert(FALSE); /*lint !e506*/
583 }
584
585 return norm;
586}
587
588/** calculates the cut efficacy for the given solution; the cut coefs are stored densely */
589static
591 SCIP* scip, /**< SCIP data structure */
592 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
593 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
594 SCIP_Real cutrhs, /**< the right hand side of the cut */
595 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
596 int cutnnz /**< the number of non-zeros in the cut */
597 )
598{
599 SCIP_VAR** vars;
600 SCIP_Real norm = 0.0;
601 SCIP_Real activity = 0.0;
602 SCIP_Real coef;
603 int i;
604
605 assert(scip != NULL);
606 assert(cutcoefs != NULL);
607 assert(cutinds != NULL);
608 assert(scip->set != NULL);
609
611
612 switch( scip->set->sepa_efficacynorm )
613 {
614 case 'e':
615 for( i = 0; i < cutnnz; ++i )
616 {
617 coef = cutcoefs[cutinds[i]];
618 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
619 norm += SQR(coef);
620 }
621 norm = sqrt(norm);
622 break;
623 case 'm':
624 for( i = 0; i < cutnnz; ++i )
625 {
626 SCIP_Real absval;
627
628 coef = cutcoefs[cutinds[i]];
629 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
630 absval = REALABS(coef);
631 norm = MAX(norm, absval);
632 }
633 break;
634 case 's':
635 for( i = 0; i < cutnnz; ++i )
636 {
637 coef = cutcoefs[cutinds[i]];
638 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
639 norm += REALABS(coef);
640 }
641 break;
642 case 'd':
643 for( i = 0; i < cutnnz; ++i )
644 {
645 coef = cutcoefs[cutinds[i]];
646 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
647 if( !SCIPisZero(scip, coef) )
648 norm = 1.0;
649 }
650 break;
651 default:
652 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
653 assert(FALSE); /*lint !e506*/
654 }
655
656 return (activity - cutrhs) / MAX(1e-6, norm);
657}
658
659/** calculates the cut efficacy for the given solution; the cut coefs are stored densely and in quad precision */
660static
662 SCIP* scip, /**< SCIP data structure */
663 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
664 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
665 SCIP_Real cutrhs, /**< the right hand side of the cut */
666 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
667 int cutnnz /**< the number of non-zeros in the cut */
668 )
669{
670 SCIP_VAR** vars;
671 SCIP_Real norm = 0.0;
672 SCIP_Real activity = 0.0;
673 SCIP_Real QUAD(coef);
674 int i;
675
676 assert(scip != NULL);
677 assert(cutcoefs != NULL);
678 assert(cutinds != NULL);
679 assert(scip->set != NULL);
680
682
683 switch( scip->set->sepa_efficacynorm )
684 {
685 case 'e':
686 for( i = 0; i < cutnnz; ++i )
687 {
688 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
689 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
690 norm += SQR(QUAD_TO_DBL(coef));
691 }
692 norm = sqrt(norm);
693 break;
694 case 'm':
695 for( i = 0; i < cutnnz; ++i )
696 {
697 SCIP_Real absval;
698
699 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
700 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
701 absval = REALABS(QUAD_TO_DBL(coef));
702 norm = MAX(norm, absval);
703 }
704 break;
705 case 's':
706 for( i = 0; i < cutnnz; ++i )
707 {
708 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
709 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
710 norm += REALABS(QUAD_TO_DBL(coef));
711 }
712 break;
713 case 'd':
714 for( i = 0; i < cutnnz; ++i )
715 {
716 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
717 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
718 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
719 norm = 1.0;
720 }
721 break;
722 default:
723 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
724 assert(FALSE); /*lint !e506*/
725 }
726
727 return (activity - cutrhs) / MAX(1e-6, norm);
728}
729
730/** safely (in the exact solving mode sense) remove all items with |a_i| or |u_i - l_i)| below the given value
731 *
732 * Returns TRUE if the cut became redundant.
733 * If it is a local cut, use local bounds, otherwise, use global bounds.
734 *
735 * * @note this method is safe for usage in exact solving mode
736 */
737static
739 SCIP* scip, /**< SCIP data structure */
740 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
741 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
742 SCIP_Real* cutrhs, /**< the right hand side of the cut */
743 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
744 int* cutnnz /**< the number of non-zeros in the cut */
745 )
746{
747 int i;
748 SCIP_VAR** vars;
749 SCIP_ROUNDMODE previousroundmode;
750
752
753 previousroundmode = SCIPintervalGetRoundingMode();
755
757
758 for( i = 0; i < *cutnnz; )
759 {
760 SCIP_Real val;
761 SCIP_Real lb;
762 SCIP_Real ub;
763 int v;
764 SCIP_Bool isfixed;
765
766 v = cutinds[i];
767 val = cutcoefs[v];
768
769 if( val == SCIP_INVALID ) /*lint !e777*/
770 val = 0.0;
771
772 /* for now we always use global bounds in exact solving mode (could be improved for local cuts in the future) */
773 lb = SCIPvarGetLbGlobal(vars[v]);
774 ub = SCIPvarGetUbGlobal(vars[v]);
775
776 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
777 isfixed = TRUE;
778 else
779 isfixed = FALSE;
780
781 if( EPSZ(val, minval) || isfixed )
782 {
783 /* adjust left and right hand sides with max contribution */
784 if( val < 0.0 )
785 {
786 if( SCIPisInfinity(scip, ub) )
787 {
788 SCIPintervalSetRoundingMode(previousroundmode);
789 return TRUE;
790 }
791 else
792 *cutrhs += (-val) * ub;
793 }
794 else
795 {
796 if( SCIPisInfinity(scip, -lb) )
797 {
798 SCIPintervalSetRoundingMode(previousroundmode);
799 return TRUE;
800 }
801 else
802 *cutrhs += (-val) * lb;
803 }
804
805 val = 0.0;
806 cutcoefs[v] = val;
807
808 /* remove non-zero entry */
809 --(*cutnnz);
810 cutinds[i] = cutinds[*cutnnz];
811 }
812 else
813 ++i;
814 }
815
816 /* relax rhs to 0, if it's very close to 0 */
817 if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
818 *cutrhs = 0.0;
819
820 SCIPintervalSetRoundingMode(previousroundmode);
821
822 return FALSE;
823}
824
825/** safely remove all items with |a_i| or |u_i - l_i)| below the given value
826 *
827 * Returns TRUE if the cut became redundant.
828 * If it is a local cut, use local bounds, otherwise, use global bounds.
829 *
830 * @note this method is safe for usage in exact solving mode
831 */
832static
834 SCIP* scip, /**< SCIP data structure */
835 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
836 SCIP_Bool cutislocal, /**< is the cut local? */
837 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
838 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
839 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
840 int* cutnnz /**< the number of non-zeros in the cut */
841 )
842{
843 int i;
844 SCIP_VAR** vars;
845
847
848 for( i = 0; i < *cutnnz; )
849 {
850 SCIP_Real QUAD(val);
851 SCIP_Real lb;
852 SCIP_Real ub;
853 int v;
854 SCIP_Bool isfixed;
855
856 v = cutinds[i];
857 QUAD_ARRAY_LOAD(val, cutcoefs, v);
858
859 if( cutislocal )
860 {
861 lb = SCIPvarGetLbLocal(vars[v]);
862 ub = SCIPvarGetUbLocal(vars[v]);
863 }
864 else
865 {
866 lb = SCIPvarGetLbGlobal(vars[v]);
867 ub = SCIPvarGetUbGlobal(vars[v]);
868 }
869
870 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
871 isfixed = TRUE;
872 else
873 isfixed = FALSE;
874
875 if( isfixed || EPSZ(QUAD_TO_DBL(val), minval) )
876 {
877 if( REALABS(QUAD_TO_DBL(val)) > QUAD_EPSILON )
878 {
879 /* adjust right hand side with max contribution */
880 if( QUAD_TO_DBL(val) < 0.0 )
881 {
882 if( SCIPisInfinity(scip, ub) )
883 return TRUE;
884 else
885 {
886 SCIPquadprecProdQD(val, val, ub);
887 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
888 }
889 }
890 else
891 {
892 if( SCIPisInfinity(scip, -lb) )
893 return TRUE;
894 else
895 {
896 SCIPquadprecProdQD(val, val, lb);
897 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
898 }
899 }
900 }
901
902 QUAD_ASSIGN(val, 0.0);
903 QUAD_ARRAY_STORE(cutcoefs, v, val);
904
905 /* remove non-zero entry */
906 --(*cutnnz);
907 cutinds[i] = cutinds[*cutnnz];
908 }
909 else
910 ++i;
911 }
912
913 /* relax rhs to 0, if it's very close to 0 */
914 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
915 QUAD_ASSIGN(*cutrhs, 0.0);
916
917 return FALSE;
918}
919
920/** safely remove all items with |a_i| or |u_i - l_i| below the given value
921 *
922 * Returns TRUE if the cut became redundant.
923 * If it is a local cut, use local bounds, otherwise, use global bounds.
924 */
925static
927 SCIP* scip, /**< SCIP data structure */
928 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
929 SCIP_Bool cutislocal, /**< is the cut local? */
930 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
931 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
932 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
933 int* cutnnz /**< the number of non-zeros in the cut */
934 )
935{
936 int i;
937 SCIP_VAR** vars;
938
940
941 /* loop over non-zeros and remove values below minval; values above QUAD_EPSILON are cancelled with their bound
942 * to avoid numerical rounding errors
943 */
944 for( i = 0; i < *cutnnz; )
945 {
946 SCIP_Real val;
947 SCIP_Real lb;
948 SCIP_Real ub;
949 int v;
950 SCIP_Bool isfixed;
951 SCIP_Real QUAD(quadprod);
952
953 v = cutinds[i];
954 val = cutcoefs[v];
955
956 if( cutislocal )
957 {
958 lb = SCIPvarGetLbLocal(vars[v]);
959 ub = SCIPvarGetUbLocal(vars[v]);
960 }
961 else
962 {
963 lb = SCIPvarGetLbGlobal(vars[v]);
964 ub = SCIPvarGetUbGlobal(vars[v]);
965 }
966
967 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
968 isfixed = TRUE;
969 else
970 isfixed = FALSE;
971
972 if( EPSZ(val, minval) || isfixed )
973 {
974 if( REALABS(val) > QUAD_EPSILON )
975 {
976 /* adjust left and right hand sides with max contribution */
977 if( val < 0.0 )
978 {
979 if( SCIPisInfinity(scip, ub) )
980 return TRUE;
981 else
982 {
983 SCIPquadprecProdDD(quadprod, -val, ub);
984 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
985 }
986 }
987 else
988 {
989 if( SCIPisInfinity(scip, -lb) )
990 return TRUE;
991 else
992 {
993 SCIPquadprecProdDD(quadprod, -val, lb);
994 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
995 }
996 }
997 }
998
999 cutcoefs[v] = 0.0;
1000
1001 /* remove non-zero entry */
1002 --(*cutnnz);
1003 cutinds[i] = cutinds[*cutnnz];
1004 }
1005 else
1006 ++i;
1007 }
1008
1009 /* relax rhs to 0, if it's very close to 0 */
1010 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
1011 QUAD_ASSIGN(*cutrhs, 0.0);
1012
1013 return FALSE;
1014}
1015
1016/** compare absolute values of coefficients in quad precision */
1017static
1018SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
1019{
1020 SCIP_Real abscoef1;
1021 SCIP_Real abscoef2;
1022 SCIP_Real QUAD(coef1);
1023 SCIP_Real QUAD(coef2);
1024 SCIP_Real* coefs = (SCIP_Real*) dataptr;
1025
1026 QUAD_ARRAY_LOAD(coef1, coefs, ind1);
1027 QUAD_ARRAY_LOAD(coef2, coefs, ind2);
1028
1029 abscoef1 = REALABS(QUAD_TO_DBL(coef1));
1030 abscoef2 = REALABS(QUAD_TO_DBL(coef2));
1031
1032 if( abscoef1 < abscoef2 )
1033 return -1;
1034 if( abscoef2 < abscoef1 )
1035 return 1;
1036
1037 return 0;
1038}
1039
1040/** compare absolute values of coefficients */
1041static
1043{
1044 SCIP_Real abscoef1;
1045 SCIP_Real abscoef2;
1046 SCIP_Real* coefs = (SCIP_Real*) dataptr;
1047
1048 abscoef1 = REALABS(coefs[ind1]);
1049 abscoef2 = REALABS(coefs[ind2]);
1050
1051 if( abscoef1 < abscoef2 )
1052 return -1;
1053 if( abscoef2 < abscoef1 )
1054 return 1;
1055
1056 return 0;
1057}
1058
1059/** change given coefficient to new given value, adjust right hand side using the variables bound;
1060 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
1061 */
1062static
1064 SCIP* scip, /**< SCIP data structure */
1065 SCIP_VAR* var, /**< variable the coefficient belongs to */
1066 SCIP_Real oldcoeff, /**< old coefficient value */
1067 SCIP_Real newcoeff, /**< new coefficient value */
1068 SCIP_Bool cutislocal, /**< is the cut local? */
1069 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
1070 )
1071{
1072 SCIP_Real QUAD(delta);
1073
1074 SCIPquadprecSumDD(delta, newcoeff, -oldcoeff);
1075
1076 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
1077 {
1079
1080 if( SCIPisInfinity(scip, ub) )
1081 return TRUE;
1082 else
1083 {
1084 SCIPquadprecProdQD(delta, delta, ub);
1085 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
1086 }
1087 }
1088 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
1089 {
1091
1092 if( SCIPisInfinity(scip, -lb) )
1093 return TRUE;
1094 else
1095 {
1096 SCIPquadprecProdQD(delta, delta, lb);
1097 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
1098 }
1099 }
1100
1101 return FALSE;
1102}
1103
1104/** change given (quad) coefficient to new given value, adjust right hand side using the variables bound;
1105 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
1106 */
1107static
1109 SCIP* scip, /**< SCIP data structure */
1110 SCIP_VAR* var, /**< variable the coefficient belongs to */
1111 QUAD(SCIP_Real oldcoeff), /**< old coefficient value */
1112 SCIP_Real newcoeff, /**< new coefficient value */
1113 SCIP_Bool cutislocal, /**< is the cut local? */
1114 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
1115 )
1116{
1117 SCIP_Real QUAD(delta);
1118
1119 SCIPquadprecSumQD(delta, -oldcoeff, newcoeff);
1120
1121 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
1122 {
1124
1125 if( SCIPisInfinity(scip, ub) )
1126 return TRUE;
1127 else
1128 {
1129 SCIPquadprecProdQD(delta, delta, ub);
1130 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
1131 }
1132 }
1133 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
1134 {
1136
1137 if( SCIPisInfinity(scip, -lb) )
1138 return TRUE;
1139 else
1140 {
1141 SCIPquadprecProdQD(delta, delta, lb);
1142 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
1143 }
1144 }
1145
1146 return FALSE;
1147}
1148
1149/** change given coefficient to new given value, adjust right hand side using the variables bound;
1150 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
1151 */
1152static
1154 SCIP* scip, /**< SCIP data structure */
1155 SCIP_VAR* var, /**< variable the coefficient belongs to */
1156 SCIP_Real oldcoeff, /**< old coefficient value */
1157 SCIP_Real newcoeff, /**< new coefficient value */
1158 SCIP_Bool cutislocal, /**< is the cut local? */
1159 SCIP_Real* cutrhs /**< pointer to adjust right hand side of cut */
1160 )
1161{
1162 SCIP_INTERVAL delta;
1163 SCIP_ROUNDMODE previousroundmode;
1164
1166
1167 previousroundmode = SCIPintervalGetRoundingMode();
1169
1170 SCIPintervalSet(&delta, newcoeff);
1171 SCIPintervalSubScalar(SCIPinfinity(scip), &delta, delta, oldcoeff);
1172
1173 if( SCIPintervalGetSup(delta) > 0 )
1174 {
1176
1177 if( SCIPisInfinity(scip, ub) )
1178 {
1179 SCIPintervalSetRoundingMode(previousroundmode);
1180 return TRUE;
1181 }
1182 else
1183 {
1184 SCIPintervalMulScalar(SCIPinfinity(scip), &delta, delta, ub);
1185 *cutrhs += SCIPintervalGetSup(delta);
1186 }
1187 }
1188 else if( SCIPintervalGetInf(delta) < 0 )
1189 {
1191
1192 if( SCIPisInfinity(scip, -lb) )
1193 {
1194 SCIPintervalSetRoundingMode(previousroundmode);
1195 return TRUE;
1196 }
1197 else
1198 {
1199 SCIPintervalMulScalar(SCIPinfinity(scip), &delta, delta, lb);
1200 *cutrhs += SCIPintervalGetSup(delta);
1201 }
1202 }
1203 else
1204 {
1205 return TRUE;
1206 }
1207
1208 return FALSE;
1209}
1210
1211
1212/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
1213 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse quad precision array;
1214 *
1215 * This is the quad precision version of cutTightenCoefs() below.
1216 */
1217static
1219 SCIP* scip, /**< SCIP data structure */
1220 SCIP_Bool cutislocal, /**< is the cut local? */
1221 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1222 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
1223 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1224 int* cutnnz, /**< the number of non-zeros in the cut */
1225 SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
1226 )
1227{
1228 int i;
1229 int nintegralvars;
1230 SCIP_Bool isintegral = TRUE;
1231 SCIP_VAR** vars;
1232 SCIP_Real QUAD(maxacttmp);
1233 SCIP_Real maxact;
1234 SCIP_Real maxabsintval = 0.0;
1235 SCIP_Real maxabscontval = 0.0;
1236
1237 QUAD_ASSIGN(maxacttmp, 0.0);
1238
1240 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1241
1242 assert(redundant != NULL);
1243 *redundant = FALSE;
1244
1245 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
1246 for( i = 0; i < *cutnnz; ++i )
1247 {
1248 SCIP_Real QUAD(val);
1249
1250 assert(cutinds[i] >= 0);
1251 assert(vars[cutinds[i]] != NULL);
1252
1253 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1254
1255 if( QUAD_TO_DBL(val) < 0.0 )
1256 {
1257 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1258
1259 if( SCIPisInfinity(scip, -lb) )
1260 return SCIP_OKAY;
1261
1262 if( cutinds[i] < nintegralvars )
1263 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
1264 else
1265 {
1266 maxabscontval = MAX(maxabscontval, -QUAD_TO_DBL(val));
1267 isintegral = FALSE;
1268 }
1269
1270 SCIPquadprecProdQD(val, val, lb);
1271 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
1272 }
1273 else
1274 {
1275 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1276
1277 if( SCIPisInfinity(scip, ub) )
1278 return SCIP_OKAY;
1279
1280 if( cutinds[i] < nintegralvars )
1281 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
1282 else
1283 {
1284 maxabscontval = MAX(maxabscontval, QUAD_TO_DBL(val));
1285 isintegral = FALSE;
1286 }
1287
1288 SCIPquadprecProdQD(val, val, ub);
1289 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
1290 }
1291 }
1292
1293 maxact = QUAD_TO_DBL(maxacttmp);
1294
1295 /* cut is redundant in activity bounds */
1296 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1297 {
1298 *redundant = TRUE;
1299 return SCIP_OKAY;
1300 }
1301
1302 /* cut is only on integral variables, try to scale to integral coefficients */
1303 if( isintegral )
1304 {
1305 SCIP_Real equiscale;
1306 SCIP_Real intscalar;
1307 SCIP_Bool success;
1308 SCIP_Real* intcoeffs;
1309
1310 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
1311
1312 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
1313
1314 for( i = 0; i < *cutnnz; ++i )
1315 {
1316 SCIP_Real QUAD(val);
1317
1318 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1319 SCIPquadprecProdQD(val, val, equiscale);
1320
1321 intcoeffs[i] = QUAD_TO_DBL(val);
1322 }
1323
1325 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
1326
1327 SCIPfreeBufferArray(scip, &intcoeffs);
1328
1329 if( success )
1330 {
1331 /* if successful, apply the scaling */
1332 intscalar *= equiscale;
1333 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
1334
1335 for( i = 0; i < *cutnnz; )
1336 {
1337 SCIP_Real QUAD(val);
1338 SCIP_Real intval;
1339
1340 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1341 SCIPquadprecProdQD(val, val, intscalar);
1342
1343 intval = SCIPround(scip, QUAD_TO_DBL(val));
1344
1345 if( chgQuadCoeffWithBound(scip, vars[cutinds[i]], QUAD(val), intval, cutislocal, QUAD(cutrhs)) )
1346 {
1347 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
1348 *redundant = TRUE;
1349 return SCIP_OKAY;
1350 }
1351
1352 if( intval != 0.0 )
1353 {
1354 QUAD_ASSIGN(val, intval);
1355 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1356 ++i;
1357 }
1358 else
1359 {
1360 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
1361 QUAD_ASSIGN(val, 0.0);
1362 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1363 --(*cutnnz);
1364 cutinds[i] = cutinds[*cutnnz];
1365 }
1366 }
1367
1368 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
1369
1370 /* recompute the maximal activity after scaling to integral values */
1371 QUAD_ASSIGN(maxacttmp, 0.0);
1372 maxabsintval = 0.0;
1373
1374 for( i = 0; i < *cutnnz; ++i )
1375 {
1376 SCIP_Real QUAD(val);
1377
1378 assert(cutinds[i] >= 0);
1379 assert(vars[cutinds[i]] != NULL);
1380
1381 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1382
1383 if( QUAD_TO_DBL(val) < 0.0 )
1384 {
1385 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1386
1387 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
1388
1389 SCIPquadprecProdQD(val, val, lb);
1390
1391 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
1392 }
1393 else
1394 {
1395 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1396
1397 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
1398
1399 SCIPquadprecProdQD(val, val, ub);
1400
1401 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
1402 }
1403 }
1404
1405 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
1406 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
1407 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
1408 }
1409 else
1410 {
1411 /* otherwise, apply the equilibrium scaling */
1412 isintegral = FALSE;
1413
1414 /* perform the scaling */
1415 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
1416 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
1417 maxabsintval *= equiscale;
1418
1419 for( i = 0; i < *cutnnz; ++i )
1420 {
1421 SCIP_Real QUAD(val);
1422
1423 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1424 SCIPquadprecProdQD(val, val, equiscale);
1425 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1426 }
1427 }
1428 }
1429 else
1430 {
1431 /* cut has integer and continuous variables, so scale it to equilibrium */
1432 SCIP_Real scale;
1433 SCIP_Real maxabsval;
1434
1435 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
1436 maxabsval = MIN(maxabsval, maxabsintval);
1437 maxabsval = MAX(maxabsval, maxabscontval);
1438
1439 scale = 1.0 / maxabsval; /*lint !e795*/
1440
1441 /* perform the scaling */
1442 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
1443 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
1444 maxabsintval *= scale;
1445
1446 for( i = 0; i < *cutnnz; ++i )
1447 {
1448 SCIP_Real QUAD(val);
1449
1450 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1451 SCIPquadprecProdQD(val, val, scale);
1452 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1453 }
1454 }
1455
1456 maxact = QUAD_TO_DBL(maxacttmp);
1457
1458 /* check again for redundancy after scaling */
1459 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1460 {
1461 *redundant = TRUE;
1462 return SCIP_OKAY;
1463 }
1464
1465 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1466 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
1467 return SCIP_OKAY;
1468
1469 /* first sort indices, so that in the following sort, the order for coefficients with same absolute value does not depend on how cutinds was initially ordered */
1470 SCIPsortInt(cutinds, *cutnnz);
1471 SCIPsortDownInd(cutinds, compareAbsCoefsQuad, (void*) cutcoefs, *cutnnz);
1472
1473 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1474 for( i = 0; i < *cutnnz; )
1475 {
1476 SCIP_Real QUAD(val);
1477
1478 if( cutinds[i] >= nintegralvars )
1479 {
1480 ++i;
1481 continue;
1482 }
1483
1484 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1485
1486 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1487
1488 if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
1489 {
1490 SCIP_Real QUAD(coef);
1491 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1492
1493 SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
1494
1495 if( isintegral )
1496 {
1497 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1499 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1500 }
1501
1502 if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
1503 {
1504 SCIP_Real QUAD(delta);
1505 SCIP_Real QUAD(tmp);
1506
1507 SCIPquadprecSumQQ(delta, -val, coef);
1508 SCIPquadprecProdQD(delta, delta, lb);
1509
1510 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1511 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1512 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
1513 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1514
1515 QUAD_ASSIGN_Q(*cutrhs, tmp);
1516
1518
1519 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
1520 {
1521 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1522 maxact = QUAD_TO_DBL(maxacttmp);
1523 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1524 }
1525 else
1526 {
1527 QUAD_ASSIGN(coef, 0.0);
1528 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1529 --(*cutnnz);
1530 cutinds[i] = cutinds[*cutnnz];
1531 continue;
1532 }
1533 }
1534 }
1535 else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
1536 {
1537 SCIP_Real QUAD(coef);
1538 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1539
1540 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
1541
1542 if( isintegral )
1543 {
1544 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1546 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1547 }
1548
1549 if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
1550 {
1551 SCIP_Real QUAD(delta);
1552 SCIP_Real QUAD(tmp);
1553
1554 SCIPquadprecSumQQ(delta, -val, coef);
1555 SCIPquadprecProdQD(delta, delta, ub);
1556
1557 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1558 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1559 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
1560 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1561
1562 QUAD_ASSIGN_Q(*cutrhs, tmp);
1563
1564 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
1565
1566 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
1567 {
1568 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1569 maxact = QUAD_TO_DBL(maxacttmp);
1570 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1571 }
1572 else
1573 {
1574 QUAD_ASSIGN(coef, 0.0);
1575 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1576 --(*cutnnz);
1577 cutinds[i] = cutinds[*cutnnz];
1578 continue;
1579 }
1580 }
1581 }
1582 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1583 break;
1584
1585 ++i;
1586 }
1587
1588 return SCIP_OKAY;
1589}
1590
1591/** multiplies a parameter for a variable in a row safely (using variable bounds and increasing the rhs)
1592 *
1593 * @return the scaled value
1594 */
1595static
1597 SCIP* scip, /**< SCIP structure */
1598 SCIP_Real val, /**< the value that should be scaled */
1599 SCIP_Real scale, /**< scaling factor */
1600 SCIP_Bool cutislocal, /**< should local or global bounds be used */
1601 SCIP_VAR* var, /**< the variable that is relevant */
1602 SCIP_Real* rhschange, /**< resulting change in rhs of row */
1603 SCIP_Bool* success /**< was the operation successful? (false if no bounds) */
1604 )
1605{
1606 SCIP_ROUNDMODE previousroundmode;
1607 SCIP_INTERVAL valinterval;
1608 SCIP_Real ub;
1609 SCIP_Real lb;
1610 SCIP_Real newval = 0.0;
1611
1613
1614 previousroundmode = SCIPintervalGetRoundingMode();
1616
1617 *rhschange = 0;
1618
1619 SCIPintervalSet(&valinterval, val);
1620 SCIPintervalMulScalar(SCIPinfinity(scip), &valinterval, valinterval, scale);
1621
1622 lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
1623 ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
1624
1625 *success = TRUE;
1626
1627 if( lb > -SCIPinfinity(scip) && lb >= 0 )
1628 {
1629 SCIPdebugMessage("Lb positive, no change in rhs needed \n");
1630 newval = SCIPintervalGetInf(valinterval);
1631 }
1632 else if(ub < SCIPinfinity(scip) && ub <= 0 )
1633 {
1634 SCIPdebugMessage("Ub negative, no change in rhs needed \n");
1635 newval = SCIPintervalGetSup(valinterval);
1636 }
1637 else if( lb > -SCIPinfinity(scip) )
1638 {
1639 newval = SCIPintervalGetInf(valinterval);
1641 *rhschange = (SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval)) * (-lb);
1642 SCIPdebugMessage("Using lb %.17g corrected by %.17g. Change to rhs: %.17g \n", SCIPvarGetLbGlobal(var), -SCIPintervalGetSup(valinterval) + SCIPintervalGetInf(valinterval), *rhschange);
1643 }
1644 else if( ub < SCIPinfinity(scip) )
1645 {
1646 newval = SCIPintervalGetSup(valinterval);
1648 *rhschange = (SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval)) * (ub);
1649 SCIPdebugMessage("Using ub %.17g corrected by %.17g. Change to rhs: %.17g \n", SCIPvarGetUbGlobal(var), SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval), *rhschange);
1650 }
1651 else
1652 {
1653 *success = FALSE;
1654 SCIPintervalSetRoundingMode(previousroundmode);
1655 return newval;
1656 }
1657
1658 SCIPintervalSetRoundingMode(previousroundmode);
1659
1660 return newval;
1661}
1662
1663/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
1664 * see cons_linear.c consdataTightenCoefs() for details;
1665 *
1666 * This is the safe version of cutTightenCoefs() below.
1667 */
1668static
1670 SCIP* scip, /**< SCIP data structure */
1671 SCIP_Bool cutislocal, /**< is the cut local? */
1672 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1673 SCIP_Real* cutrhs, /**< the right hand side of the cut */
1674 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1675 int* cutnnz, /**< the number of non-zeros in the cut */
1676 SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
1677 )
1678{ /*lint --e{644}*/
1679 int i;
1680 int nintegralvars;
1681 SCIP_Bool isintegral = TRUE;
1682 SCIP_VAR** vars;
1683 SCIP_INTERVAL maxact;
1684 SCIP_INTERVAL tmp;
1685 SCIP_Real maxabsintval = 0.0;
1686 SCIP_Real maxabscontval = 0.0;
1687 SCIP_ROUNDMODE previousroundmode;
1688 SCIP_MIRINFO* mirinfo = NULL;
1689
1691
1692 if( SCIPisCertified(scip) )
1693 {
1695 assert(mirinfo != NULL);
1696 }
1697
1698 SCIPintervalSet(&maxact, 0.0);
1699
1701 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1702
1703 assert(redundant != NULL);
1704 *redundant = FALSE;
1705
1706 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
1707 for( i = 0; i < *cutnnz; ++i )
1708 {
1709 SCIP_Real val;
1710
1711 assert(cutinds[i] >= 0);
1712 assert(vars[cutinds[i]] != NULL);
1713
1714 val = cutcoefs[cutinds[i]];
1715
1716 if( val < 0.0 )
1717 {
1718 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1719
1720 if( SCIPisInfinity(scip, -lb) )
1721 return SCIP_OKAY;
1722
1723 if( cutinds[i] < nintegralvars )
1724 maxabsintval = MAX(maxabsintval, -val);
1725 else
1726 {
1727 maxabscontval = MAX(maxabscontval, -val);
1728 isintegral = FALSE;
1729 }
1730
1731 SCIPintervalSet(&tmp, val);
1732 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, lb);
1733 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
1734 }
1735 else
1736 {
1737 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1738
1739 if( SCIPisInfinity(scip, ub) )
1740 return SCIP_OKAY;
1741
1742 if( cutinds[i] < nintegralvars )
1743 maxabsintval = MAX(maxabsintval, val);
1744 else
1745 {
1746 maxabscontval = MAX(maxabscontval, val);
1747 isintegral = FALSE;
1748 }
1749
1750 SCIPintervalSet(&tmp, val);
1751 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, ub);
1752 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
1753 }
1754 }
1755
1756 /* cut is redundant in activity bounds */
1757 if( SCIPintervalGetSup(maxact) <= *cutrhs )
1758 {
1759 *redundant = TRUE;
1760 return SCIP_OKAY;
1761 }
1762
1763 previousroundmode = SCIPintervalGetRoundingMode();
1764
1765 /* cut is only on integral variables, try to scale to integral coefficients */
1766 if( isintegral )
1767 {
1768 SCIP_Real equiscale;
1769 SCIP_Real intscalar;
1770 SCIP_Bool success;
1771 SCIP_Real* intcoeffs;
1772 SCIP_Real rhschange;
1773
1774 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
1775
1776 equiscale = 1.0 / MAX(maxabscontval, maxabsintval);
1777
1778 for( i = 0; i < *cutnnz; ++i )
1779 {
1780 SCIP_Real val;
1781
1782 val = cutcoefs[cutinds[i]];
1783 val *= equiscale;
1784
1785 intcoeffs[i] = val;
1786 }
1787
1789 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
1790
1791 SCIPfreeBufferArray(scip, &intcoeffs);
1792
1793 if( success )
1794 {
1795 /* if successful, apply the scaling */
1797 intscalar *= equiscale;
1798
1799 *cutrhs *= intscalar;
1800
1801 if( SCIPisCertified(scip) )
1802 {
1803 assert(mirinfo != NULL);
1804 mirinfo->scale = intscalar;
1805 }
1806
1807 for( i = 0; i < *cutnnz; )
1808 {
1809 SCIP_Real val;
1810 SCIP_Real intval;
1811
1812 val = cutcoefs[cutinds[i]];
1813 val = scaleValSafely(scip, val, intscalar, cutislocal, vars[cutinds[i]], &rhschange, &success);
1814
1815 *cutrhs += rhschange;
1816
1817 if( !success )
1818 {
1819 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
1820 *redundant = TRUE;
1821 SCIPintervalSetRoundingMode(previousroundmode);
1822 return SCIP_OKAY;
1823 }
1824 intval = SCIPround(scip, val);
1825
1826 if( chgCoeffWithBoundSafely(scip, vars[cutinds[i]], val, intval, cutislocal, cutrhs) )
1827 {
1828 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
1829 SCIPintervalSetRoundingMode(previousroundmode);
1830 *redundant = TRUE;
1831 return SCIP_OKAY;
1832 }
1833
1834 if( intval != 0.0 )
1835 {
1836 val = intval;
1837 cutcoefs[cutinds[i]] = val;
1838 ++i;
1839 }
1840 else
1841 {
1842 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
1843 val = 0.0;
1844 cutcoefs[cutinds[i]] = val;
1845 --(*cutnnz);
1846 cutinds[i] = cutinds[*cutnnz];
1847 }
1848 }
1849
1850 if( SCIPisCertified(scip) )
1851 {
1852 assert(mirinfo != NULL);
1853 mirinfo->unroundedrhs = *cutrhs;
1854 }
1855 *cutrhs = floor(*cutrhs); /*lint !e835*/
1856
1857 /* recompute the maximal activity after scaling to integral values */
1858 SCIPintervalSet(&maxact, 0.0);
1859 maxabsintval = 0.0;
1860
1861 for( i = 0; i < *cutnnz; ++i )
1862 {
1863 SCIP_Real val;
1864
1865 assert(cutinds[i] >= 0);
1866 assert(vars[cutinds[i]] != NULL);
1867
1868 val = cutcoefs[cutinds[i]];
1869
1870 if( val < 0.0 )
1871 {
1872 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1873
1874 maxabsintval = MAX(maxabsintval, -val);
1875
1876 SCIPintervalSet(&tmp, val);
1877 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, lb);
1878 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
1879 }
1880 else
1881 {
1882 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1883
1884 maxabsintval = MAX(maxabsintval, val);
1885
1886 SCIPintervalSet(&tmp, val);
1887 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, ub);
1888 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
1889 }
1890 }
1891
1892 assert(EPSISINT(SCIPintervalGetSup(maxact), 1e-4));/*lint !e666*/
1893 /* check again for redundancy */
1894 if( SCIPisFeasLE(scip, SCIPintervalGetSup(maxact), *cutrhs) )
1895 {
1896 *redundant = TRUE;
1897 SCIPintervalSetRoundingMode(previousroundmode);
1898 return SCIP_OKAY;
1899 }
1900 }
1901 else
1902 {
1903 /* otherwise, apply the equilibrium scaling */
1904
1905 /* perform the scaling */
1906 SCIPintervalMulScalar(SCIPinfinity(scip), &maxact, maxact, equiscale);
1908
1909 *cutrhs *= equiscale;
1910 maxabsintval *= equiscale;
1911 if( SCIPisCertified(scip) )
1912 {
1913 assert(mirinfo != NULL);
1914 mirinfo->scale = equiscale;
1915 }
1916
1917 for( i = 0; i < *cutnnz; ++i )
1918 {
1919 SCIP_Real val;
1920
1921 val = cutcoefs[cutinds[i]];
1922 val = scaleValSafely(scip, val, equiscale, cutislocal, vars[cutinds[i]], &rhschange, &success);
1923
1924 if( !success )
1925 {
1926 *redundant = TRUE;
1927 SCIPintervalSetRoundingMode(previousroundmode);
1928 return SCIP_OKAY;
1929 }
1930 cutcoefs[cutinds[i]] = val;
1931 *cutrhs += rhschange;
1932 }
1933 }
1934 }
1935 else
1936 {
1937 /* cut has integer and continuous variables, so scale it to equilibrium */
1938 SCIP_Real scale;
1939 SCIP_Real maxabsval;
1940 SCIP_Bool success;
1941 SCIP_Real rhschange;
1942
1943 maxabsval = SCIPintervalGetSup(maxact) - *cutrhs;
1944 maxabsval = MIN(maxabsval, maxabsintval);
1945 maxabsval = MAX(maxabsval, maxabscontval);
1946
1947 scale = 1.0 / maxabsval; /*lint !e795*/
1948
1949 /* perform the scaling */
1950 SCIPintervalSet(&maxact, scale);
1952 *cutrhs *= scale;
1953 maxabsintval *= scale;
1954 if( SCIPisCertified(scip) )
1955 {
1956 assert(mirinfo != NULL);
1957 mirinfo->scale = scale;
1958 }
1959
1960 for( i = 0; i < *cutnnz; ++i )
1961 {
1962 SCIP_Real val;
1963
1964 val = cutcoefs[cutinds[i]];
1965 val = scaleValSafely(scip, val, scale, cutislocal, vars[cutinds[i]], &rhschange, &success);
1966
1967 *cutrhs += rhschange;
1968
1969 if( !success )
1970 {
1971 *redundant = TRUE;
1972 SCIPintervalSetRoundingMode(previousroundmode);
1973 return SCIP_OKAY;
1974 }
1975 cutcoefs[cutinds[i]] = val;
1976 }
1977 }
1978
1979 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1980 if( SCIPisGT(scip, SCIPintervalGetSup(maxact) - maxabsintval, *cutrhs) )
1981 {
1982 SCIPintervalSetRoundingMode(previousroundmode);
1983 return SCIP_OKAY;
1984 }
1985
1986 SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
1987
1988#ifdef SCIP_DISABLED_CODE
1989 /** @todo implement and certify coefficient tightening for cuts in exact solving mode */
1990 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1991 for( i = 0; i < *cutnnz && FALSE; )
1992 {
1993 SCIP_Real QUAD(val);
1994
1995 if( cutinds[i] >= nintegralvars )
1996 {
1997 ++i;
1998 continue;
1999 }
2000
2001 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
2002
2003 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
2004
2005 if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
2006 {
2007 SCIP_Real QUAD(coef);
2008 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2009
2010 SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
2011
2012 if( isintegral )
2013 {
2014 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
2016 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
2017 }
2018
2019 if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
2020 {
2021 SCIP_Real QUAD(delta);
2022 SCIP_Real QUAD(tmp);
2023
2024 SCIPquadprecSumQQ(delta, -val, coef);
2025 SCIPquadprecProdQD(delta, delta, lb);
2026
2027 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
2028 SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2029 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
2030 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
2031
2032 QUAD_ASSIGN_Q(*cutrhs, tmp);
2033
2035
2036 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
2037 {
2038 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2039 maxact = QUAD_TO_DBL(maxacttmp);
2040 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
2041 }
2042 else
2043 {
2044 QUAD_ASSIGN(coef, 0.0);
2045 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
2046 --(*cutnnz);
2047 cutinds[i] = cutinds[*cutnnz];
2048 continue;
2049 }
2050 }
2051 }
2052 else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
2053 {
2054 SCIP_Real QUAD(coef);
2055 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2056
2057 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
2058
2059 if( isintegral )
2060 {
2061 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
2063 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
2064 }
2065
2066 if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
2067 {
2068 SCIP_Real QUAD(delta);
2069 SCIP_Real QUAD(tmp);
2070
2071 SCIPquadprecSumQQ(delta, -val, coef);
2072 SCIPquadprecProdQD(delta, delta, ub);
2073
2074 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
2075 SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2076 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
2077 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
2078
2079 QUAD_ASSIGN_Q(*cutrhs, tmp);
2080
2081 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
2082
2083 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
2084 {
2085 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2086 maxact = QUAD_TO_DBL(maxacttmp);
2087 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
2088 }
2089 else
2090 {
2091 QUAD_ASSIGN(coef, 0.0);
2092 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
2093 --(*cutnnz);
2094 cutinds[i] = cutinds[*cutnnz];
2095 continue;
2096 }
2097 }
2098 }
2099 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
2100 break;
2101
2102 ++i;
2103 }
2104#endif /*lint --e{438}*/
2105
2106 return SCIP_OKAY;
2107}
2108
2109
2110/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
2111 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse array;
2112 */
2113static
2115 SCIP* scip, /**< SCIP data structure */
2116 SCIP_Bool cutislocal, /**< is the cut local? */
2117 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
2118 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
2119 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
2120 int* cutnnz, /**< the number of non-zeros in the cut */
2121 SCIP_Bool* redundant /**< pointer to return whtether the cut was detected to be redundant */
2122 )
2123{
2124 int i;
2125 int nintegralvars;
2126 SCIP_Bool isintegral = TRUE;
2127 SCIP_VAR** vars;
2128 SCIP_Real QUAD(maxacttmp);
2129 SCIP_Real maxact;
2130 SCIP_Real maxabsintval = 0.0;
2131 SCIP_Real maxabscontval = 0.0;
2132
2134
2135 QUAD_ASSIGN(maxacttmp, 0.0);
2136
2138 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
2139
2140 assert(redundant != NULL);
2141 *redundant = FALSE;
2142
2143 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
2144 for( i = 0; i < *cutnnz; ++i )
2145 {
2146 SCIP_Real val;
2147 SCIP_Real QUAD(quadprod);
2148
2149 assert(cutinds[i] >= 0);
2150 assert(vars[cutinds[i]] != NULL);
2151
2152 val = cutcoefs[cutinds[i]];
2153
2154 if( val < 0.0 )
2155 {
2156 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2157
2158 if( SCIPisInfinity(scip, -lb) )
2159 return SCIP_OKAY;
2160
2161 if( cutinds[i] < nintegralvars )
2162 maxabsintval = MAX(maxabsintval, -val);
2163 else
2164 {
2165 maxabscontval = MAX(maxabscontval, -val);
2166 isintegral = FALSE;
2167 }
2168
2169 SCIPquadprecProdDD(quadprod, val, lb);
2170 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2171 }
2172 else
2173 {
2174 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2175
2176 if( SCIPisInfinity(scip, ub) )
2177 return SCIP_OKAY;
2178
2179 if( cutinds[i] < nintegralvars )
2180 maxabsintval = MAX(maxabsintval, val);
2181 else
2182 {
2183 maxabscontval = MAX(maxabscontval, val);
2184 isintegral = FALSE;
2185 }
2186
2187 SCIPquadprecProdDD(quadprod, val, ub);
2188 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2189 }
2190 }
2191
2192 maxact = QUAD_TO_DBL(maxacttmp);
2193
2194 /* cut is redundant in activity bounds */
2195 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
2196 {
2197 *redundant = TRUE;
2198 return SCIP_OKAY;
2199 }
2200
2201 /* cut is only on integral variables, try to scale to integral coefficients */
2202 if( isintegral )
2203 {
2204 SCIP_Real equiscale;
2205 SCIP_Real intscalar;
2206 SCIP_Bool success;
2207 SCIP_Real* intcoeffs;
2208
2209 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
2210
2211 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
2212
2213 for( i = 0; i < *cutnnz; ++i )
2214 {
2215 SCIP_Real val;
2216
2217 val = equiscale * cutcoefs[cutinds[i]];
2218
2219 intcoeffs[i] = val;
2220 }
2221
2223 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
2224
2225 SCIPfreeBufferArray(scip, &intcoeffs);
2226
2227 if( success )
2228 {
2229 /* if successful, apply the scaling */
2230 intscalar *= equiscale;
2231 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
2232
2233 for( i = 0; i < *cutnnz; )
2234 {
2235 SCIP_Real val;
2236 SCIP_Real intval;
2237
2238 val = cutcoefs[cutinds[i]];
2239 val *= intscalar;
2240
2241 intval = SCIPround(scip, val);
2242
2243 if( chgCoeffWithBound(scip, vars[cutinds[i]], val, intval, cutislocal, QUAD(cutrhs)) )
2244 {
2245 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
2246 *redundant = TRUE;
2247 return SCIP_OKAY;
2248 }
2249
2250 if( intval != 0.0 )
2251 {
2252 cutcoefs[cutinds[i]] = intval;
2253 ++i;
2254 }
2255 else
2256 {
2257 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
2258 cutcoefs[cutinds[i]] = 0.0;
2259 --(*cutnnz);
2260 cutinds[i] = cutinds[*cutnnz];
2261 }
2262 }
2263
2264 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
2265
2266 /* recompute the maximal activity after scaling to integral values */
2267 QUAD_ASSIGN(maxacttmp, 0.0);
2268 maxabsintval = 0.0;
2269
2270 for( i = 0; i < *cutnnz; ++i )
2271 {
2272 SCIP_Real val;
2273 SCIP_Real QUAD(quadprod);
2274
2275 assert(cutinds[i] >= 0);
2276 assert(vars[cutinds[i]] != NULL);
2277
2278 val = cutcoefs[cutinds[i]];
2279
2280 if( val < 0.0 )
2281 {
2282 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2283
2284 maxabsintval = MAX(maxabsintval, -val);
2285
2286 SCIPquadprecProdDD(quadprod, val, lb);
2287 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2288 }
2289 else
2290 {
2291 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2292
2293 maxabsintval = MAX(maxabsintval, val);
2294
2295 SCIPquadprecProdDD(quadprod, val, ub);
2296 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2297 }
2298 }
2299
2300 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
2301 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
2302 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
2303 }
2304 else
2305 {
2306 /* otherwise, apply the equilibrium scaling */
2307 isintegral = FALSE;
2308
2309 /* perform the scaling */
2310 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
2311 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
2312 maxabsintval *= equiscale;
2313
2314 for( i = 0; i < *cutnnz; ++i )
2315 cutcoefs[cutinds[i]] *= equiscale;
2316 }
2317 }
2318 else
2319 {
2320 /* cut has integer and continuous variables, so scale it to equilibrium */
2321 SCIP_Real scale;
2322 SCIP_Real maxabsval;
2323
2324 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
2325 maxabsval = MIN(maxabsval, maxabsintval);
2326 maxabsval = MAX(maxabsval, maxabscontval);
2327
2328 scale = 1.0 / maxabsval; /*lint !e795*/
2329
2330 /* perform the scaling */
2331 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
2332 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
2333 maxabsintval *= scale;
2334
2335 for( i = 0; i < *cutnnz; ++i )
2336 cutcoefs[cutinds[i]] *= scale;
2337 }
2338
2339 maxact = QUAD_TO_DBL(maxacttmp);
2340
2341 /* check again for redundancy after scaling */
2342 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
2343 {
2344 *redundant = TRUE;
2345 return SCIP_OKAY;
2346 }
2347
2348 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
2349 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
2350 return SCIP_OKAY;
2351
2352 /* first sort indices, so that in the following sort, the order for coefficients with same absolute value does not depend on how cutinds was initially ordered */
2353 SCIPsortInt(cutinds, *cutnnz);
2354 SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
2355
2356 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
2357 for( i = 0; i < *cutnnz; )
2358 {
2359 SCIP_Real val;
2360
2361 if( cutinds[i] >= nintegralvars )
2362 {
2363 ++i;
2364 continue;
2365 }
2366
2367 val = cutcoefs[cutinds[i]];
2368
2369 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
2370
2371 if( val < 0.0 && SCIPisLE(scip, maxact + val, QUAD_TO_DBL(*cutrhs)) )
2372 {
2373 SCIP_Real QUAD(coef);
2374 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2375
2376 SCIPquadprecSumQQ(coef, -maxacttmp, *cutrhs);
2377
2378 if( isintegral )
2379 {
2380 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
2382 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
2383 }
2384
2385 if( QUAD_TO_DBL(coef) > val )
2386 {
2387 SCIP_Real QUAD(delta);
2388 SCIP_Real QUAD(tmp);
2389
2390 SCIPquadprecSumQD(delta, coef, -val);
2391 SCIPquadprecProdQD(delta, delta, lb);
2392
2393 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
2394 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2395 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
2396 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
2397
2398 QUAD_ASSIGN_Q(*cutrhs, tmp);
2399
2401
2402 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
2403 {
2404 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2405 maxact = QUAD_TO_DBL(maxacttmp);
2406 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
2407 }
2408 else
2409 {
2410 cutcoefs[cutinds[i]] = 0.0;
2411 --(*cutnnz);
2412 cutinds[i] = cutinds[*cutnnz];
2413 continue;
2414 }
2415 }
2416 }
2417 else if( val > 0.0 && SCIPisLE(scip, maxact - val, QUAD_TO_DBL(*cutrhs)) )
2418 {
2419 SCIP_Real QUAD(coef);
2420 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2421
2422 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
2423
2424 if( isintegral )
2425 {
2426 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
2428 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
2429 }
2430
2431 if( QUAD_TO_DBL(coef) < val )
2432 {
2433 SCIP_Real QUAD(delta);
2434 SCIP_Real QUAD(tmp);
2435
2436 SCIPquadprecSumQD(delta, coef, -val);
2437 SCIPquadprecProdQD(delta, delta, ub);
2438
2439 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
2440 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2441 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
2442 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
2443
2444 QUAD_ASSIGN_Q(*cutrhs, tmp);
2445
2447
2448 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
2449 {
2450 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2451 maxact = QUAD_TO_DBL(maxacttmp);
2452 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
2453 }
2454 else
2455 {
2456 cutcoefs[cutinds[i]] = 0.0;
2457 --(*cutnnz);
2458 cutinds[i] = cutinds[*cutnnz];
2459 continue;
2460 }
2461 }
2462 }
2463 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
2464 break;
2465
2466 ++i;
2467 }
2468
2469 return SCIP_OKAY;
2470}
2471
2472/** perform activity based coefficient tightening on the given cut; returns TRUE if the cut was detected
2473 * to be redundant due to activity bounds
2474 *
2475 * See also cons_linear.c:consdataTightenCoefs().
2476 */
2478 SCIP* scip, /**< SCIP data structure */
2479 SCIP_Bool cutislocal, /**< is the cut local? */
2480 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
2481 SCIP_Real* cutrhs, /**< the right hand side of the cut */
2482 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
2483 int* cutnnz, /**< the number of non-zeros in the cut */
2484 int* nchgcoefs /**< number of changed coefficients */
2485 )
2486{
2487 int i;
2488 int nintegralvars;
2489 SCIP_VAR** vars;
2490 SCIP_Real* absvals;
2491 SCIP_Real QUAD(maxacttmp);
2492 SCIP_Real maxact;
2493 SCIP_Real maxabsval = 0.0;
2494 SCIP_Bool redundant = FALSE;
2495
2496 assert(nchgcoefs != NULL);
2497
2498 QUAD_ASSIGN(maxacttmp, 0.0);
2499
2501 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
2502 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &absvals, *cutnnz) );
2503
2504 assert(nchgcoefs != NULL);
2505 *nchgcoefs = 0;
2506
2507 for( i = 0; i < *cutnnz; ++i )
2508 {
2509 SCIP_Real QUAD(quadprod);
2510
2511 assert(cutinds[i] >= 0);
2512 assert(vars[cutinds[i]] != NULL);
2513
2514 if( cutcoefs[i] < 0.0 )
2515 {
2516 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2517
2518 if( SCIPisInfinity(scip, -lb) )
2519 goto TERMINATE;
2520
2521 if( cutinds[i] < nintegralvars )
2522 {
2523 maxabsval = MAX(maxabsval, -cutcoefs[i]);
2524 absvals[i] = -cutcoefs[i];
2525 }
2526 else
2527 absvals[i] = 0.0;
2528
2529 SCIPquadprecProdDD(quadprod, lb, cutcoefs[i]);
2530 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2531 }
2532 else
2533 {
2534 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2535
2536 if( SCIPisInfinity(scip, ub) )
2537 goto TERMINATE;
2538
2539 if( cutinds[i] < nintegralvars )
2540 {
2541 maxabsval = MAX(maxabsval, cutcoefs[i]);
2542 absvals[i] = cutcoefs[i];
2543 }
2544 else
2545 absvals[i] = 0.0;
2546
2547 SCIPquadprecProdDD(quadprod, ub, cutcoefs[i]);
2548 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2549 }
2550 }
2551
2552 maxact = QUAD_TO_DBL(maxacttmp);
2553
2554 /* cut is redundant in activity bounds */
2555 if( SCIPisFeasLE(scip, maxact, *cutrhs) )
2556 {
2557 redundant = TRUE;
2558 goto TERMINATE;
2559 }
2560
2561 /* terminate, because coefficient tightening cannot be performed; also excludes the case in which no integral variable is present */
2562 if( SCIPisGT(scip, maxact - maxabsval, *cutrhs) )
2563 goto TERMINATE;
2564
2565 SCIPsortDownRealRealInt(absvals, cutcoefs, cutinds, *cutnnz);
2566 SCIPfreeBufferArray(scip, &absvals);
2567
2568 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
2569 for( i = 0; i < *cutnnz; ++i )
2570 {
2571 /* due to sorting, we can exit if we reached a continuous variable: all further integral variables have 0 coefficents anyway */
2572 if( cutinds[i] >= nintegralvars )
2573 break;
2574
2575 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
2576
2577 if( cutcoefs[i] < 0.0 && SCIPisLE(scip, maxact + cutcoefs[i], *cutrhs) )
2578 {
2579 SCIP_Real coef = (*cutrhs) - maxact;
2580 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2581
2582 coef = SCIPfloor(scip, coef);
2583
2584 if( coef > cutcoefs[i] )
2585 {
2586 SCIP_Real QUAD(delta);
2587 SCIP_Real QUAD(tmp);
2588
2589 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
2590 SCIPquadprecProdQD(delta, delta, lb);
2591
2592 SCIPquadprecSumQD(tmp, delta, *cutrhs);
2593 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2594 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp), lb,
2595 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
2596
2597 *cutrhs = QUAD_TO_DBL(tmp);
2598
2599 assert(!SCIPisPositive(scip, coef));
2600
2601 ++(*nchgcoefs);
2602
2603 if( SCIPisNegative(scip, coef) )
2604 {
2605 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2606 maxact = QUAD_TO_DBL(maxacttmp);
2607 cutcoefs[i] = coef;
2608 }
2609 else
2610 {
2611 --(*cutnnz);
2612 cutinds[i] = cutinds[*cutnnz];
2613 cutcoefs[i] = cutcoefs[*cutnnz];
2614 continue;
2615 }
2616 }
2617 }
2618 else if( cutcoefs[i] > 0.0 && SCIPisLE(scip, maxact - cutcoefs[i], *cutrhs) )
2619 {
2620 SCIP_Real coef = maxact - (*cutrhs);
2621 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2622
2623 coef = SCIPceil(scip, coef);
2624
2625 if( coef < cutcoefs[i] )
2626 {
2627 SCIP_Real QUAD(delta);
2628 SCIP_Real QUAD(tmp);
2629
2630 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
2631 SCIPquadprecProdQD(delta, delta, ub);
2632
2633 SCIPquadprecSumQD(tmp, delta, *cutrhs);
2634 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2635 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp),
2636 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
2637
2638 *cutrhs = QUAD_TO_DBL(tmp);
2639
2640 assert(!SCIPisNegative(scip, coef));
2641
2642 ++(*nchgcoefs);
2643
2644 if( SCIPisPositive(scip, coef) )
2645 {
2646 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2647 maxact = QUAD_TO_DBL(maxacttmp);
2648 cutcoefs[i] = coef;
2649 }
2650 else
2651 {
2652 --(*cutnnz);
2653 cutinds[i] = cutinds[*cutnnz];
2654 cutcoefs[i] = cutcoefs[*cutnnz];
2655 continue;
2656 }
2657 }
2658 }
2659 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
2660 break;
2661 }
2662
2663 TERMINATE:
2664 SCIPfreeBufferArrayNull(scip, &absvals);
2665
2666 return redundant;
2667}
2668
2669/* =========================================== aggregation row =========================================== */
2670
2671
2672/** create an empty aggregation row
2673 *
2674 * @note By default, this data structure uses quad precision via double-double arithmetic, i.e., it allocates a
2675 * SCIP_Real array of length two times SCIPgetNVars() for storing the coefficients. In exact solving mode, we
2676 * cannot use quad precision because we need to control the ronding mode, hence only the first SCIPgetNVars()
2677 * entries are used.
2678 */
2680 SCIP* scip, /**< SCIP data structure */
2681 SCIP_AGGRROW** aggrrow /**< pointer to return aggregation row */
2682 )
2683{
2684 int nvars;
2685 assert(scip != NULL);
2686 assert(aggrrow != NULL);
2687
2688 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
2689
2691
2693 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->inds, nvars) );
2694
2695 BMSclearMemoryArray((*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars));
2696
2697 (*aggrrow)->local = FALSE;
2698 (*aggrrow)->nnz = 0;
2699 (*aggrrow)->rank = 0;
2700 QUAD_ASSIGN((*aggrrow)->rhs, 0.0);
2701 (*aggrrow)->rowsinds = NULL;
2702 (*aggrrow)->slacksign = NULL;
2703 (*aggrrow)->rowweights = NULL;
2704 (*aggrrow)->nrows = 0;
2705 (*aggrrow)->rowssize = 0;
2706
2707 return SCIP_OKAY;
2708}
2709
2710/** free a aggregation row */
2712 SCIP* scip, /**< SCIP data structure */
2713 SCIP_AGGRROW** aggrrow /**< pointer to aggregation row that should be freed */
2714 )
2715{
2716 int nvars;
2717
2718 assert(scip != NULL);
2719 assert(aggrrow != NULL);
2720
2722
2723 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->inds, nvars);
2724 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)); /*lint !e647*/
2725 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowsinds, (*aggrrow)->rowssize);
2726 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->slacksign, (*aggrrow)->rowssize);
2727 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowweights, (*aggrrow)->rowssize);
2728 SCIPfreeBlockMemory(scip, aggrrow);
2729}
2730
2731/** output aggregation row to file stream */
2733 SCIP* scip, /**< SCIP data structure */
2734 SCIP_AGGRROW* aggrrow, /**< pointer to return aggregation row */
2735 FILE* file /**< output file (or NULL for standard output) */
2736 )
2737{
2738 SCIP_VAR** vars;
2739 SCIP_MESSAGEHDLR* messagehdlr;
2740 int i;
2741
2742 assert(scip != NULL);
2743 assert(aggrrow != NULL);
2744
2746 assert(vars != NULL);
2747
2748 messagehdlr = SCIPgetMessagehdlr(scip);
2749 assert(messagehdlr);
2750
2751 /* print coefficients */
2752 if( aggrrow->nnz == 0 )
2753 SCIPmessageFPrintInfo(messagehdlr, file, "0 ");
2754
2755 for( i = 0; i < aggrrow->nnz; ++i )
2756 {
2757 SCIP_Real QUAD(val);
2758
2759 QUAD_ARRAY_LOAD(val, aggrrow->vals, aggrrow->inds[i]);
2760 assert(SCIPvarGetProbindex(vars[aggrrow->inds[i]]) == aggrrow->inds[i]);
2761 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", QUAD_TO_DBL(val), SCIPvarGetName(vars[aggrrow->inds[i]]));
2762 }
2763
2764 /* print right hand side */
2765 SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", QUAD_TO_DBL(aggrrow->rhs));
2766}
2767
2768/** copy a aggregation row */
2770 SCIP* scip, /**< SCIP data structure */
2771 SCIP_AGGRROW** aggrrow, /**< pointer to return aggregation row */
2772 SCIP_AGGRROW* source /**< source aggregation row */
2773 )
2774{
2775 int nvars;
2776
2777 assert(scip != NULL);
2778 assert(aggrrow != NULL);
2779 assert(source != NULL);
2780
2782 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
2783
2784 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->vals, source->vals, QUAD_ARRAY_SIZE(nvars)) );
2785 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->inds, source->inds, nvars) );
2786 (*aggrrow)->nnz = source->nnz;
2787 QUAD_ASSIGN_Q((*aggrrow)->rhs, source->rhs);
2788
2789 if( source->nrows > 0 )
2790 {
2791 assert(source->rowsinds != NULL);
2792 assert(source->slacksign != NULL);
2793 assert(source->rowweights != NULL);
2794
2795 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowsinds, source->rowsinds, source->nrows) );
2796 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->slacksign, source->slacksign, source->nrows) );
2797 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowweights, source->rowweights, source->nrows) );
2798 }
2799 else
2800 {
2801 (*aggrrow)->rowsinds = NULL;
2802 (*aggrrow)->slacksign = NULL;
2803 (*aggrrow)->rowweights = NULL;
2804 }
2805
2806 (*aggrrow)->nrows = source->nrows;
2807 (*aggrrow)->rowssize = source->nrows;
2808 (*aggrrow)->rank = source->rank;
2809 (*aggrrow)->local = source->local;
2810
2811 return SCIP_OKAY;
2812}
2813
2814/** add weighted row to aggregation row */
2816 SCIP* scip, /**< SCIP data structure */
2817 SCIP_AGGRROW* aggrrow, /**< aggregation row */
2818 SCIP_ROW* row, /**< row to add to aggregation row */
2819 SCIP_Real weight, /**< scale for adding given row to aggregation row */
2820 int sidetype /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
2821 )
2822{
2823 SCIP_Real QUAD(quadprod);
2824 SCIP_Real sideval;
2825 SCIP_Bool uselhs;
2826 int i;
2827
2828 assert(row->lppos >= 0);
2829
2830 /* update local flag */
2831 aggrrow->local = aggrrow->local || row->local;
2832
2833 /* update rank */
2834 aggrrow->rank = MAX(row->rank, aggrrow->rank);
2835
2836 i = aggrrow->nrows++;
2837
2838 if( aggrrow->nrows > aggrrow->rowssize )
2839 {
2840 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
2841 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
2842 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
2843 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
2844 aggrrow->rowssize = newsize;
2845 }
2846 aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
2847 aggrrow->rowweights[i] = weight;
2848
2849 if( sidetype == -1 )
2850 {
2851 assert( ! SCIPisInfinity(scip, -row->lhs) );
2852 uselhs = TRUE;
2853 }
2854 else if( sidetype == 1 )
2855 {
2856 assert( ! SCIPisInfinity(scip, row->rhs) );
2857 uselhs = FALSE;
2858 }
2859 else
2860 {
2861 /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
2862 * If possible, use the side that leads to a positive slack value in the summation.
2863 */
2864 if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
2865 uselhs = TRUE;
2866 else
2867 uselhs = FALSE;
2868 }
2869
2870 if( uselhs )
2871 {
2872 aggrrow->slacksign[i] = -1;
2873 sideval = row->lhs - row->constant;
2874 if( row->integral )
2875 sideval = SCIPceil(scip, sideval); /* row is integral: round left hand side up */
2876 }
2877 else
2878 {
2879 aggrrow->slacksign[i] = +1;
2880 sideval = row->rhs - row->constant;
2881 if( row->integral )
2882 sideval = SCIPfloor(scip, sideval); /* row is integral: round right hand side up */
2883 }
2884
2885 SCIPquadprecProdDD(quadprod, weight, sideval);
2886 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
2887
2888 /* add up coefficients */
2889 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
2890
2891 return SCIP_OKAY;
2892}
2893
2894/** add weighted row to aggregation row
2895 *
2896 * @note this method is the variant of SCIPaggrRowAddRow that is safe to use in exact solving mode
2897 */
2899 SCIP* scip, /**< SCIP data structure */
2900 SCIP_AGGRROW* aggrrow, /**< aggregation row */
2901 SCIP_ROW* row, /**< row to add to aggregation row */
2902 SCIP_Real weight, /**< scale for adding given row to aggregation row */
2903 int sidetype, /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
2904 SCIP_Bool* success /**< was the row added successfully */
2905 )
2906{
2907 SCIP_Real sideval;
2908 SCIP_Real sidevalchg;
2909 SCIP_Bool uselhs;
2910 SCIP_ROW* userow;
2911 SCIP_ROWEXACT* rowexact;
2912 SCIP_ROUNDMODE previousroundmode;
2913 int i;
2914
2916 assert(success != NULL);
2917
2918 /* update local flag */
2919 aggrrow->local = aggrrow->local || row->local;
2920
2921 /* update rank */
2922 aggrrow->rank = MAX(row->rank, aggrrow->rank);
2923
2924 i = aggrrow->nrows++;
2925
2926 if( aggrrow->nrows > aggrrow->rowssize )
2927 {
2928 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
2929 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
2930 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
2931 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
2932 aggrrow->rowssize = newsize;
2933 }
2934 aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
2935 aggrrow->rowweights[i] = weight;
2936
2937 if( sidetype == -1 )
2938 {
2939 assert(!SCIPisInfinity(scip, -row->lhs));
2940 uselhs = TRUE;
2941 }
2942 else if( sidetype == 1 )
2943 {
2944 assert(!SCIPisInfinity(scip, row->rhs));
2945 uselhs = FALSE;
2946 }
2947 else
2948 {
2949 /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
2950 * If possible, use the side that leads to a positive slack value in the summation.
2951 */
2952 if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
2953 uselhs = TRUE;
2954 else
2955 uselhs = FALSE;
2956 }
2957 rowexact = SCIProwGetRowExact(row);
2958 if( !SCIProwExactHasFpRelax(rowexact) )
2959 {
2960 *success = FALSE;
2961 return SCIP_OKAY;
2962 }
2963 else if( SCIProwExactGetRowRhs(rowexact) != NULL && weight >= 0.0 )
2964 userow = SCIProwExactGetRowRhs(rowexact);
2965 else
2966 userow = row;
2967
2968 aggrrow->slacksign[i] = uselhs ? -1 : 1;
2969
2970 previousroundmode = SCIPintervalGetRoundingMode();
2971
2972 if( uselhs )
2973 {
2975 sideval = userow->lhs - userow->constant;
2976#ifdef SCIP_DISABLED_CODE
2977 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
2978 /* row is integral? round left hand side up */
2979 if( userow->integral )
2980 sideval = ceil(sideval)
2981#endif
2982 }
2983 else
2984 {
2986 sideval = userow->rhs - userow->constant;
2987#ifdef SCIP_DISABLED_CODE
2988 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
2989 /* row is integral? round right hand side down */
2990 if( userow->integral )
2991 sideval = floor(sideval);
2992#endif
2993 }
2994
2996 sidevalchg = QUAD_TO_DBL(aggrrow->rhs);
2997 sidevalchg += sideval * weight;
2998 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
2999
3000 /* add up coefficients */
3001 *success = TRUE;
3002 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, aggrrow->inds, aggrrow->vals, &aggrrow->nnz, userow, weight, &sidevalchg, success) );
3003
3004 sidevalchg += QUAD_TO_DBL(aggrrow->rhs);
3005 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
3006
3007 SCIPintervalSetRoundingMode(previousroundmode);
3008
3009 return SCIP_OKAY;
3010}
3011
3012/** Removes a given variable @p var from position @p pos the aggregation row and updates the right-hand side according
3013 * to sign of the coefficient, i.e., rhs -= coef * bound, where bound = lb if coef >= 0 and bound = ub, otherwise.
3014 *
3015 * @note: The choice of global or local bounds depend on the validity (global or local) of the aggregation row.
3016 *
3017 * @note: The list of non-zero indices will be updated by swapping the last non-zero index to @p pos.
3018 */
3020 SCIP* scip, /**< SCIP data structure */
3021 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3022 SCIP_VAR* var, /**< variable that should be removed */
3023 int pos, /**< position of the variable in the aggregation row */
3024 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
3025 )
3026{
3027 SCIP_Real QUAD(val);
3028 int v;
3029
3030 assert(valid != NULL);
3031 assert(pos >= 0);
3032
3033 v = aggrrow->inds[pos];
3035
3036 QUAD_ARRAY_LOAD(val, aggrrow->vals, v);
3037
3038 *valid = TRUE;
3039
3040 /* adjust left and right hand sides with max contribution */
3041 if( QUAD_TO_DBL(val) < 0.0 )
3042 {
3044
3045 if( SCIPisInfinity(scip, ub) )
3046 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
3047 else
3048 {
3049 SCIPquadprecProdQD(val, val, ub);
3050 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
3051 }
3052 }
3053 else
3054 {
3056
3057 if( SCIPisInfinity(scip, -lb) )
3058 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
3059 else
3060 {
3061 SCIPquadprecProdQD(val, val, lb);
3062 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
3063 }
3064 }
3065
3066 QUAD_ASSIGN(val, 0.0);
3067 QUAD_ARRAY_STORE(aggrrow->vals, v, val);
3068
3069 /* remove non-zero entry */
3070 --(aggrrow->nnz);
3071 aggrrow->inds[pos] = aggrrow->inds[aggrrow->nnz];
3072
3073 if( SCIPisInfinity(scip, QUAD_HI(aggrrow->rhs)) )
3074 *valid = FALSE;
3075}
3076
3077/** add the objective function with right-hand side @p rhs and scaled by @p scale to the aggregation row */
3079 SCIP* scip, /**< SCIP data structure */
3080 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3081 SCIP_Real rhs, /**< right-hand side of the artificial row */
3082 SCIP_Real scale /**< scalar */
3083 )
3084{
3085 SCIP_VAR** vars;
3086 SCIP_Real QUAD(val);
3087 int nvars;
3088
3089 assert(scip != NULL);
3090 assert(aggrrow != NULL);
3091
3094
3095 /* add all variables straight forward if the aggregation row is empty */
3096 if( aggrrow->nnz == 0 )
3097 {
3098 int i;
3099 for( i = 0; i < nvars; ++i )
3100 {
3102
3103 /* skip all variables with zero objective coefficient */
3104 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
3105 continue;
3106
3107 QUAD_ASSIGN(val, scale * SCIPvarGetObj(vars[i])); /*lint !e665*/
3108 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
3109 aggrrow->inds[aggrrow->nnz++] = i;
3110 }
3111
3112 /* add right-hand side value */
3113 QUAD_ASSIGN(aggrrow->rhs, scale * rhs); /*lint !e665*/
3114 }
3115 else
3116 {
3117 int i;
3118 SCIP_Real QUAD(quadprod);
3119 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
3120 for( i = 0 ; i < nvars; ++i )
3121 {
3122 SCIP_Real varobj;
3124
3125 /* skip all variables with zero objective coefficient */
3126 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
3127 continue;
3128
3129 QUAD_ARRAY_LOAD(val, aggrrow->vals, i); /* val = aggrrow->vals[i] */
3130
3131 if( QUAD_HI(val) == 0.0 )
3132 aggrrow->inds[aggrrow->nnz++] = i;
3133
3134 varobj = SCIPvarGetObj(vars[i]);
3135 SCIPquadprecProdDD(quadprod, scale, varobj);
3136 SCIPquadprecSumQQ(val, val, quadprod);
3137
3138 /* the value must not be exactly zero due to sparsity pattern */
3139 QUAD_HI(val) = NONZERO(QUAD_HI(val));
3140 assert(QUAD_HI(val) != 0.0);
3141
3142 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
3143 }
3144
3145 /* add right-hand side value */
3146 SCIPquadprecProdDD(quadprod, scale, rhs);
3147 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
3148 }
3149
3150 return SCIP_OKAY;
3151}
3152
3153/** add weighted constraint to the aggregation row */
3155 SCIP* scip, /**< SCIP data structure */
3156 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3157 int* inds, /**< variable problem indices in constraint to add to the aggregation row */
3158 SCIP_Real* vals, /**< values of constraint to add to the aggregation row */
3159 int len, /**< length of constraint to add to the aggregation row */
3160 SCIP_Real rhs, /**< right hand side of constraint to add to the aggregation row */
3161 SCIP_Real weight, /**< (positive) scale for adding given constraint to the aggregation row */
3162 int rank, /**< rank to use for given constraint */
3163 SCIP_Bool local /**< is constraint only valid locally */
3164 )
3165{
3166 SCIP_Real QUAD(quadprod);
3167 int i;
3168
3169 assert(weight >= 0.0);
3170 assert(!SCIPisInfinity(scip, REALABS(weight * rhs)));
3171
3172 /* update local flag */
3173 aggrrow->local = aggrrow->local || local;
3174
3175 /* update rank */
3176 aggrrow->rank = MAX(rank, aggrrow->rank);
3177
3178 /* add right hand side value */
3179 SCIPquadprecProdDD(quadprod, weight, rhs);
3180 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
3181
3182 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
3183 for( i = 0 ; i < len; ++i )
3184 {
3185 SCIP_Real QUAD(val);
3186 int probindex = inds[i];
3187
3188 QUAD_ARRAY_LOAD(val, aggrrow->vals, probindex); /* val = aggrrow->vals[probindex] */
3189
3190 if( QUAD_HI(val) == 0.0 )
3191 aggrrow->inds[aggrrow->nnz++] = probindex;
3192
3193 SCIPquadprecProdDD(quadprod, vals[i], weight);
3194 SCIPquadprecSumQQ(val, val, quadprod);
3195
3196 /* the value must not be exactly zero due to sparsity pattern */
3197 QUAD_HI(val) = NONZERO(QUAD_HI(val));
3198 assert(QUAD_HI(val) != 0.0);
3199
3200 QUAD_ARRAY_STORE(aggrrow->vals, probindex, val);
3201 }
3202
3203 return SCIP_OKAY;
3204}
3205
3206/** version for use in exact solving mode of SCIPaggrRowClear() */
3208 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3209 )
3210{
3211 int i;
3212
3213 /* in exact solving mode, we do not use quad precision, because we need to control the rounding mode; hence, we only
3214 * use and clear the first SCIPgetNVars() entries
3215 */
3216 for( i = 0; i < aggrrow->nnz; ++i )
3217 {
3218 aggrrow->vals[aggrrow->inds[i]] = 0.0;
3219 }
3220
3221 aggrrow->nnz = 0;
3222 aggrrow->nrows = 0;
3223 aggrrow->rank = 0;
3224 QUAD_ASSIGN(aggrrow->rhs, 0.0);
3225 aggrrow->local = FALSE;
3226}
3227
3228/** clear all entries int the aggregation row but don't free memory */
3230 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3231 )
3232{
3233 int i;
3234 SCIP_Real QUAD(tmp);
3235
3236 QUAD_ASSIGN(tmp, 0.0);
3237
3238 for( i = 0; i < aggrrow->nnz; ++i )
3239 {
3240 QUAD_ARRAY_STORE(aggrrow->vals, aggrrow->inds[i], tmp);
3241 }
3242
3243 aggrrow->nnz = 0;
3244 aggrrow->nrows = 0;
3245 aggrrow->rank = 0;
3246 QUAD_ASSIGN(aggrrow->rhs, 0.0);
3247 aggrrow->local = FALSE;
3248}
3249
3250/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
3251 *
3252 * @return the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
3253 */
3255 SCIP* scip, /**< SCIP data structure */
3256 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3257 )
3258{
3259 return calcEfficacyNormQuad(scip, aggrrow->vals, aggrrow->inds, aggrrow->nnz);
3260}
3261
3262/** adds one row to the aggregation row
3263 *
3264 * @note this method differs from SCIPaggrRowAddRow() by providing some additional parameters required for
3265 * SCIPaggrRowSumRows()
3266 */
3267static
3269 SCIP* scip, /**< SCIP data structure */
3270 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3271 SCIP_ROW* row, /**< the row to add */
3272 SCIP_Real weight, /**< weight of row to add */
3273 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
3274 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
3275 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
3276 int maxaggrlen, /**< maximal length of aggregation row */
3277 SCIP_Bool* rowtoolong /**< is the aggregated row too long */
3278 )
3279{
3280 SCIP_Real QUAD(quadprod);
3281 SCIP_Real sideval;
3282 SCIP_Bool uselhs;
3283 int i;
3284
3285 assert( rowtoolong != NULL );
3286 *rowtoolong = FALSE;
3287
3288 if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
3289 {
3290 return SCIP_OKAY;
3291 }
3292
3293 if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
3294 {
3296
3297 if( stat == SCIP_BASESTAT_LOWER )
3298 {
3300 uselhs = TRUE;
3301 }
3302 else if( stat == SCIP_BASESTAT_UPPER )
3303 {
3305 uselhs = FALSE;
3306 }
3307 else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
3308 uselhs = TRUE;
3309 else
3310 uselhs = FALSE;
3311 }
3312 else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
3313 uselhs = TRUE;
3314 else
3315 uselhs = FALSE;
3316
3317 if( uselhs )
3318 {
3320
3321 if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
3322 return SCIP_OKAY;
3323
3324 sideval = row->lhs - row->constant;
3325 /* row is integral? round left hand side up */
3326 if( row->integral )
3327 sideval = SCIPceil(scip, sideval);
3328 }
3329 else
3330 {
3332
3333 if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
3334 return SCIP_OKAY;
3335
3336 sideval = row->rhs - row->constant;
3337 /* row is integral? round right hand side down */
3338 if( row->integral )
3339 sideval = SCIPfloor(scip, sideval);
3340 }
3341
3342 /* add right hand side, update rank and local flag */
3343 SCIPquadprecProdDD(quadprod, sideval, weight);
3344 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
3345 aggrrow->rank = MAX(aggrrow->rank, row->rank);
3346 aggrrow->local = aggrrow->local || row->local;
3347
3348 /* ensure the array for storing the row information is large enough */
3349 i = aggrrow->nrows++;
3350 if( aggrrow->nrows > aggrrow->rowssize )
3351 {
3352 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
3353 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
3354 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
3355 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
3356 aggrrow->rowssize = newsize;
3357 }
3358
3359 /* add information of addditional row */
3360 aggrrow->rowsinds[i] = row->lppos;
3361 aggrrow->rowweights[i] = weight;
3362 aggrrow->slacksign[i] = uselhs ? -1 : 1;
3363
3364 /* add up coefficients */
3365 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
3366
3367 /* check if row is too long now */
3368 if( aggrrow->nnz > maxaggrlen )
3369 *rowtoolong = TRUE;
3370
3371 return SCIP_OKAY;
3372}
3373
3374/** adds one row to the aggregation row
3375 *
3376 * @note this method differs from SCIPaggrRowAddRowSafely() by providing some additional parameters required for
3377 * SCIPaggrRowSumRows()
3378 *
3379 * @note this method is the variant of addOneRow() that is safe to use in exact solving mode
3380 */
3381static
3383 SCIP* scip, /**< SCIP data structure */
3384 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3385 SCIP_ROW* row, /**< the row to add */
3386 SCIP_Real weight, /**< weight of row to add */
3387 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
3388 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
3389 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
3390 int maxaggrlen, /**< maximal length of aggregation row */
3391 SCIP_Bool* rowtoolong, /**< is the aggregated row too long */
3392 SCIP_Bool* rowused, /**< was the row really added? */
3393 SCIP_Bool* success, /**< was the row added successfully? */
3394 SCIP_Bool* lhsused /**< was the lhs or the rhs of the row used? */
3395 )
3396{
3397 SCIP_Real sideval;
3398 SCIP_Real sidevalchg;
3399 SCIP_Bool uselhs;
3400 SCIP_ROW* userow;
3401 SCIP_ROWEXACT* rowexact;
3402 SCIP_ROUNDMODE previousroundmode;
3403 int i;
3404
3406 assert(rowtoolong != NULL);
3407 *rowtoolong = FALSE;
3408 *rowused = FALSE;
3409
3410 if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
3411 {
3412 return SCIP_OKAY;
3413 }
3414
3415 if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
3416 {
3418
3419 if( stat == SCIP_BASESTAT_LOWER )
3420 {
3422 uselhs = TRUE;
3423 }
3424 else if( stat == SCIP_BASESTAT_UPPER )
3425 {
3427 uselhs = FALSE;
3428 }
3429 else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
3430 uselhs = TRUE;
3431 else
3432 uselhs = FALSE;
3433 }
3434 else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
3435 uselhs = TRUE;
3436 else
3437 uselhs = FALSE;
3438
3439 rowexact = SCIProwGetRowExact(row);
3440 if( !SCIProwExactHasFpRelax(rowexact) )
3441 {
3442 *success = FALSE;
3443 return SCIP_OKAY;
3444 }
3445 else if( SCIProwExactGetRowRhs(rowexact) != NULL && weight >= 0.0 )
3446 userow = SCIProwExactGetRowRhs(rowexact);
3447 else
3448 userow = row;
3449
3450 previousroundmode = SCIPintervalGetRoundingMode();
3451
3452 if( uselhs )
3453 {
3454 *lhsused = TRUE;
3456
3457 if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
3458 return SCIP_OKAY;
3459
3461
3462 sideval = userow->lhs - userow->constant;
3463#ifdef SCIP_DISABLED_CODE
3464 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
3465 /* row is integral? round left hand side up */
3466 if( userow->integral )
3467 sideval = ceil(sideval);
3468#endif
3469 }
3470 else
3471 {
3472 *lhsused = FALSE;
3474
3475 if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
3476 return SCIP_OKAY;
3477
3479
3480 sideval = userow->rhs - userow->constant;
3481#ifdef SCIP_DISABLED_CODE
3482 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
3483 /* row is integral? round right hand side down */
3484 if( userow->integral )
3485 sideval = floor(sideval);
3486#endif
3487 }
3488
3490
3491 sidevalchg = QUAD_TO_DBL(aggrrow->rhs);
3492 sidevalchg += sideval * weight;
3493 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
3494
3495 aggrrow->rank = MAX(aggrrow->rank, userow->rank);
3496 aggrrow->local = aggrrow->local || userow->local;
3497
3498 /* ensure the array for storing the row information is large enough */
3499 i = aggrrow->nrows++;
3500 *rowused = TRUE;
3501 if( aggrrow->nrows > aggrrow->rowssize )
3502 {
3503 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
3504 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
3505 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
3506 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
3507 aggrrow->rowssize = newsize;
3508 }
3509
3510 /* add information of addditional row */
3511 aggrrow->rowsinds[i] = row->lppos;
3512 aggrrow->rowweights[i] = weight;
3513 aggrrow->slacksign[i] = uselhs ? -1 : 1;
3514
3515 /* add up coefficients */
3516 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, aggrrow->inds, aggrrow->vals, &aggrrow->nnz, userow, weight, &sidevalchg, success) );
3517
3518 sidevalchg += QUAD_TO_DBL(aggrrow->rhs);
3519 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
3520
3521 /* check if row is too long now */
3522 if( aggrrow->nnz > maxaggrlen )
3523 *rowtoolong = TRUE;
3524
3525 SCIPintervalSetRoundingMode(previousroundmode);
3526
3527 return SCIP_OKAY;
3528}
3529
3530/** aggregate rows using the given weights; the current content of the aggregation row, \p aggrrow, is overwritten
3531 *
3532 * @note this method is safe for usage in exact solving mode
3533 */
3535 SCIP* scip, /**< SCIP data structure */
3536 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3537 SCIP_Real* weights, /**< row weights in row summation */
3538 int* rowinds, /**< array to store indices of non-zero entries of the weights array, or NULL */
3539 int nrowinds, /**< number of non-zero entries in weights array, -1 if rowinds is NULL */
3540 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
3541 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
3542 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
3543 int maxaggrlen, /**< maximal length of aggregation row */
3544 SCIP_Bool* valid /**< is the aggregation valid */
3545 )
3546{
3547 SCIP_AGGRROW* certificaterow = NULL;
3548 SCIP_ROW** rows;
3549 SCIP_ROW** usedrows = NULL;
3550 SCIP_ROW** negslackrows = NULL;
3551 SCIP_VAR** vars;
3552 SCIP_Real* usedweights = NULL;
3553 SCIP_Real* negslackweights = NULL;
3554 int nrows;
3555 int nvars;
3556 int k;
3557 int nusedrows;
3558 int nnegslackrows;
3559 SCIP_Bool rowtoolong;
3560 SCIP_Bool rowused, rowusedcert, lhsused;
3561
3562 assert( scip != NULL );
3563 assert( aggrrow != NULL );
3564 assert( valid != NULL );
3565
3567 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
3568
3569 if( SCIPisExact(scip) )
3570 SCIPaggrRowClearSafely(aggrrow);
3571 else
3572 SCIPaggrRowClear(aggrrow);
3573 *valid = TRUE;
3574 lhsused = FALSE;
3575 nusedrows = 0;
3576 nnegslackrows = 0;
3577
3578 SCIPdebugMessage("Summing up %d rows in aggrrow \n", nrowinds);
3579
3580 if( SCIPisCertified(scip) )
3581 {
3582 SCIP_CALL( SCIPallocBufferArray(scip, &usedrows, nrows) );
3583 SCIP_CALL( SCIPallocBufferArray(scip, &usedweights, nrows) );
3584 SCIP_CALL( SCIPallocBufferArray(scip, &negslackrows, nrows) );
3585 SCIP_CALL( SCIPallocBufferArray(scip, &negslackweights, nrows) );
3586 SCIP_CALL( SCIPaggrRowCreate(scip, &certificaterow) );
3587 }
3588
3589 if( rowinds != NULL && nrowinds > -1 )
3590 {
3591 for( k = 0; k < nrowinds; ++k )
3592 {
3593 if( !SCIPisExact(scip) )
3594 {
3595 SCIP_CALL( addOneRow(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
3596
3597 if( rowtoolong )
3598 *valid = FALSE;
3599 }
3600 else /*lint --e{644}*/
3601 {
3602 SCIPdebugMessage("Adding %g times row: ", weights[rowinds[k]]);
3603 SCIPdebug(SCIPprintRow(scip, rows[rowinds[k]], NULL));
3604 SCIP_CALL( addOneRowSafely(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal,
3605 negslack, maxaggrlen, &rowtoolong, &rowused, valid, &lhsused) );
3606
3607 if( rowtoolong )
3608 *valid = FALSE;
3609
3610 if( !(*valid) )
3611 break;
3612
3613 if( certificaterow != NULL )
3614 {
3615 assert(usedrows != NULL);
3616 assert(usedweights != NULL);
3617 assert(negslackrows != NULL);
3618 assert(negslackweights != NULL);
3619
3620 SCIP_ROW* row = rows[rowinds[k]];
3621 SCIP_Bool integral = FALSE;
3622
3623 /* just exclude the negative continuous slacks for the certificate rows */
3624 if( row->integral &&
3625 ((!lhsused && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant)) ||
3627 {
3628 SCIPdebugMessage("row has integral slack\n");
3629 rowusedcert = FALSE;
3630 integral = TRUE;
3631 }
3632 else
3633 {
3634 /* the certificate row may exceed the limit maxaggrlen */
3635 SCIP_CALL( addOneRowSafely(scip, certificaterow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis,
3636 allowlocal, 0, nvars, &rowtoolong, &rowusedcert, valid, &lhsused) );
3637 assert(!rowtoolong);
3638 }
3639 if( rowusedcert )
3640 {
3641 usedrows[nusedrows] = rows[rowinds[k]];
3642 usedweights[nusedrows] = weights[rowinds[k]];
3643 nusedrows++;
3644 }
3645 if( rowused && !rowusedcert && !integral )
3646 {
3647 SCIPdebugMessage("row has negative continous slack\n");
3648 assert( (lhsused && weights[rowinds[k]] >= 0) || ((!lhsused) && weights[rowinds[k]] <= 0) || row->integral );
3649 negslackrows[nnegslackrows] = rows[rowinds[k]];
3650 negslackweights[nnegslackrows] = -weights[rowinds[k]];
3651 nnegslackrows++;
3652 }
3653 }
3654 }
3655
3656 if( !(*valid) )
3657 break;
3658 }
3659 }
3660 else
3661 {
3662 for( k = 0; k < nrows; ++k )
3663 {
3664 if( weights[k] != 0.0 )
3665 {
3666 if( !SCIPisExact(scip) )
3667 {
3668 SCIP_CALL( addOneRow(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
3669
3670 if( rowtoolong )
3671 *valid = FALSE;
3672 }
3673 else
3674 {
3675 SCIPdebugMessage("Adding %g times row: ", weights[k]);
3676 SCIPdebug(SCIPprintRow(scip, rows[k], NULL));
3677 SCIP_CALL( addOneRowSafely(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack,
3678 maxaggrlen, &rowtoolong, &rowused, valid, &lhsused) );
3679
3680 if( rowtoolong )
3681 *valid = FALSE;
3682
3683 if( !(*valid) )
3684 break;
3685
3686 if( certificaterow != NULL )
3687 {
3688 assert(usedrows != NULL);
3689 assert(usedweights != NULL);
3690 assert(negslackrows != NULL);
3691 assert(negslackweights != NULL);
3692
3693 SCIP_ROW* row = rows[k];
3694 SCIP_Bool integral = FALSE;
3695
3696 /* just exclude the negative continuous slacks for the certificate rows */
3697 if( row->integral &&
3698 ((!lhsused && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant)) ||
3700 {
3701 rowusedcert = FALSE;
3702 SCIPdebugMessage("row has integral slack\n");
3703 integral = TRUE;
3704 }
3705 else
3706 {
3707 /* the certificate row may exceed the limit maxaggrlen */
3708 SCIP_CALL( addOneRowSafely(scip, certificaterow, rows[k], weights[k], sidetypebasis, allowlocal, 0,
3709 nvars, &rowtoolong, &rowusedcert, valid, &lhsused) );
3710 assert(!rowtoolong);
3711 }
3712 if( rowusedcert )
3713 {
3714 usedrows[nusedrows] = rows[k];
3715 usedweights[nusedrows] = weights[k];
3716 nusedrows++;
3717 }
3718 if( rowused && !rowusedcert && !integral )
3719 {
3720 SCIPdebugMessage("row has negative continous slack\n");
3721 assert( (lhsused && weights[k] >= 0) || ((!lhsused) && weights[k] <= 0) || row->integral );
3722 negslackrows[nnegslackrows] = rows[k];
3723 negslackweights[nnegslackrows] = -weights[k];
3724 nnegslackrows++;
3725 }
3726 }
3727 }
3728
3729 if( !(*valid) )
3730 break;
3731 }
3732 }
3733 }
3734
3735 if( *valid )
3736 {
3738
3739 if( certificaterow != NULL )
3740 {
3741 SCIPaggrRowRemoveZeros(scip, certificaterow, FALSE, valid);
3742 SCIP_CALL( SCIPaddCertificateAggrInfo(scip, certificaterow, usedrows, usedweights, certificaterow->nrows,
3743 negslackrows, negslackweights, nnegslackrows) );
3744 }
3745 }
3746
3747 if( certificaterow != NULL )
3748 {
3749 SCIPaggrRowFree(scip, &certificaterow);
3750 SCIPfreeBufferArray(scip, &negslackweights);
3751 SCIPfreeBufferArray(scip, &negslackrows);
3752 SCIPfreeBufferArray(scip, &usedweights);
3753 SCIPfreeBufferArray(scip, &usedrows);
3754 }
3755
3756 return SCIP_OKAY;
3757}
3758
3759/** checks for cut redundancy and performs activity based coefficient tightening;
3760 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
3761 * to remove small coefficients (relative to the maximum absolute coefficient)
3762 */
3763static
3765 SCIP* scip, /**< SCIP data structure */
3766 SCIP_Bool cutislocal, /**< is the cut a local cut */
3767 int* cutinds, /**< variable problem indices of non-zeros in cut */
3768 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
3769 int* nnz, /**< number non-zeros coefficients of cut */
3770 SCIP_Real* cutrhs, /**< right hand side of cut */
3771 SCIP_Bool* success /**< pointer to return whether post-processing was successful or cut is redundant */
3772 )
3773{
3774 int i;
3775 SCIP_Bool redundant;
3776 SCIP_Real maxcoef;
3777 SCIP_Real minallowedcoef;
3778 SCIP_Real QUAD(rhs);
3779
3780 assert(scip != NULL);
3781 assert(cutinds != NULL);
3782 assert(cutcoefs != NULL);
3783 assert(cutrhs != NULL);
3784 assert(success != NULL);
3785
3786 *success = FALSE;
3787
3788 QUAD_ASSIGN(rhs, *cutrhs);
3789
3790 if( removeZeros(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz) )
3791 {
3792 /* right hand side was changed to infinity -> cut is redundant */
3793 return SCIP_OKAY;
3794 }
3795
3796 if( *nnz == 0 )
3797 return SCIP_OKAY;
3798
3799 SCIP_CALL( cutTightenCoefs(scip, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz, &redundant) );
3800
3801 if( redundant )
3802 {
3803 /* cut is redundant */
3804 return SCIP_OKAY;
3805 }
3806
3807 maxcoef = 0.0;
3808 for( i = 0; i < *nnz; ++i )
3809 {
3810 SCIP_Real absval = REALABS(cutcoefs[cutinds[i]]);
3811 maxcoef = MAX(absval, maxcoef);
3812 }
3813
3814 maxcoef /= scip->set->sepa_maxcoefratio;
3815 minallowedcoef = SCIPsumepsilon(scip);
3816 minallowedcoef = MAX(minallowedcoef, maxcoef);
3817
3818 *success = ! removeZeros(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz);
3819 *cutrhs = QUAD_TO_DBL(rhs);
3820
3821 return SCIP_OKAY;
3822}
3823
3824
3825/** checks for cut redundancy and performs activity based coefficient tightening;
3826 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
3827 * to remove small coefficients (relative to the maximum absolute coefficient).
3828 * The cutcoefs must be a quad precision array, i.e. allocated with size
3829 * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
3830 * macros.
3831 */
3832static
3834 SCIP* scip, /**< SCIP data structure */
3835 SCIP_Bool cutislocal, /**< is the cut a local cut */
3836 int* cutinds, /**< variable problem indices of non-zeros in cut */
3837 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
3838 int* nnz, /**< number non-zeros coefficients of cut */
3839 QUAD(SCIP_Real* cutrhs), /**< right hand side of cut */
3840 SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
3841 )
3842{
3843 int i;
3844 SCIP_Bool redundant;
3845 SCIP_Real maxcoef;
3846 SCIP_Real minallowedcoef;
3847
3848 assert(scip != NULL);
3849 assert(cutinds != NULL);
3850 assert(cutcoefs != NULL);
3851 assert(QUAD_HI(cutrhs) != NULL);
3852 assert(success != NULL);
3853
3854 *success = FALSE;
3855
3856 if( removeZerosQuad(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz) )
3857 {
3858 /* right hand side was changed to infinity -> cut is redundant */
3859 return SCIP_OKAY;
3860 }
3861
3862 if( *nnz == 0 )
3863 return SCIP_OKAY;
3864
3865 SCIP_CALL( cutTightenCoefsQuad(scip, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz, &redundant) );
3866 if( redundant )
3867 {
3868 /* cut is redundant */
3869 return SCIP_OKAY;
3870 }
3871
3872 maxcoef = 0.0;
3873 for( i = 0; i < *nnz; ++i )
3874 {
3875 SCIP_Real abscoef;
3876 SCIP_Real QUAD(coef);
3877 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]); /* coef = cutcoefs[cutinds[i]] */
3878 abscoef = REALABS(QUAD_TO_DBL(coef));
3879 maxcoef = MAX(abscoef, maxcoef);
3880 }
3881
3882 maxcoef /= scip->set->sepa_maxcoefratio;
3883 minallowedcoef = SCIPsumepsilon(scip);
3884 minallowedcoef = MAX(minallowedcoef, maxcoef);
3885
3886 *success = ! removeZerosQuad(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz);
3887
3888 return SCIP_OKAY;
3889}
3890
3891/** checks for cut redundancy and performs activity based coefficient tightening;
3892 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
3893 * to remove small coefficients (relative to the maximum absolute coefficient).
3894 * The cutcoefs must be a quad precision array, i.e. allocated with size
3895 * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
3896 * macros.
3897 */
3898static
3900 SCIP* scip, /**< SCIP data structure */
3901 SCIP_Bool cutislocal, /**< is the cut a local cut */
3902 int* cutinds, /**< variable problem indices of non-zeros in cut */
3903 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
3904 int* nnz, /**< number non-zeros coefficients of cut */
3905 SCIP_Real* cutrhs, /**< right hand side of cut */
3906 SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
3907 )
3908{
3909 int i;
3910 SCIP_Bool redundant;
3911 SCIP_Real maxcoef;
3912 SCIP_Real minallowedcoef;
3913
3915
3916 assert(scip != NULL);
3917 assert(cutinds != NULL);
3918 assert(cutcoefs != NULL);
3919 assert(cutrhs != NULL);
3920 assert(success != NULL);
3921
3922 *success = FALSE;
3923
3924 if( removeZerosSafely(scip, SCIPfeastol(scip), cutcoefs, cutrhs, cutinds, nnz) )
3925 {
3926 /* right hand side was changed to infinity -> cut is redundant */
3927 return SCIP_OKAY;
3928 }
3929
3930 if( *nnz == 0 )
3931 return SCIP_OKAY;
3932
3933 SCIP_CALL( cutTightenCoefsSafely(scip, cutislocal, cutcoefs, cutrhs, cutinds, nnz, &redundant) );
3934 if( redundant )
3935 {
3936 /* cut is redundant */
3937 return SCIP_OKAY;
3938 }
3939
3940 maxcoef = 0.0;
3941 for( i = 0; i < *nnz; ++i )
3942 {
3943 SCIP_Real abscoef;
3944 SCIP_Real coef;
3945 coef = cutcoefs[cutinds[i]];
3946 abscoef = REALABS(coef);
3947 maxcoef = MAX(abscoef, maxcoef);
3948 }
3949
3950 maxcoef /= scip->set->sepa_maxcoefratio;
3951 minallowedcoef = SCIPsumepsilon(scip);
3952 minallowedcoef = MAX(minallowedcoef, maxcoef);
3953
3954 *success = ! removeZerosSafely(scip, minallowedcoef, cutcoefs, cutrhs, cutinds, nnz);
3955
3956 return SCIP_OKAY;
3957}
3958
3959/** removes almost zero entries from the aggregation row. */
3961 SCIP* scip, /**< SCIP datastructure */
3962 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3963 SCIP_Bool useglbbounds, /**< consider global bound although the cut is local? */
3964 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
3965 )
3966{
3967 assert(aggrrow != NULL);
3968 assert(valid != NULL);
3969
3970 if( SCIPisExact(scip) )
3971 {
3972 SCIP_Real rhs;
3973 rhs = QUAD_TO_DBL(aggrrow->rhs);
3974 *valid = !removeZerosSafely(scip, SCIPsumepsilon(scip), aggrrow->vals, &rhs, aggrrow->inds, &aggrrow->nnz);
3975 QUAD_ASSIGN(aggrrow->rhs, rhs);
3976 return;
3977 }
3978
3979 *valid = ! removeZerosQuad(scip, SCIPsumepsilon(scip), useglbbounds ? FALSE : aggrrow->local, aggrrow->vals,
3980 QUAD(&aggrrow->rhs), aggrrow->inds, &aggrrow->nnz);
3981}
3982
3983/** get number of aggregated rows */
3985 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3986 )
3987{
3988 assert(aggrrow != NULL);
3989
3990 return aggrrow->nrows;
3991}
3992
3993/** get array with lp positions of rows used in aggregation */
3995 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3996 )
3997{
3998 assert(aggrrow != NULL);
3999 assert(aggrrow->rowsinds != NULL || aggrrow->nrows == 0);
4000
4001 return aggrrow->rowsinds;
4002}
4003
4004/** get array with weights of aggregated rows */
4006 SCIP_AGGRROW* aggrrow /**< the aggregation row */
4007 )
4008{
4009 assert(aggrrow != NULL);
4010 assert(aggrrow->rowweights != NULL || aggrrow->nrows == 0);
4011
4012 return aggrrow->rowweights;
4013}
4014
4015/** checks whether a given row has been added to the aggregation row */
4017 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
4018 SCIP_ROW* row /**< row for which it is checked whether it has been added to the aggregation */
4019 )
4020{
4021 int i;
4022 int rowind;
4023
4024 assert(aggrrow != NULL);
4025 assert(row != NULL);
4026
4027 rowind = SCIProwGetLPPos(row);
4028
4029 for( i = 0; i < aggrrow->nrows; ++i )
4030 {
4031 if( aggrrow->rowsinds[i] == rowind )
4032 return TRUE;
4033 }
4034
4035 return FALSE;
4036}
4037
4038/** gets the array of corresponding variable problem indices for each non-zero in the aggregation row */
4040 SCIP_AGGRROW* aggrrow /**< aggregation row */
4041 )
4042{
4043 assert(aggrrow != NULL);
4044
4045 return aggrrow->inds;
4046}
4047
4048/** gets the number of non-zeros in the aggregation row */
4050 SCIP_AGGRROW* aggrrow /**< aggregation row */
4051 )
4052{
4053 assert(aggrrow != NULL);
4054
4055 return aggrrow->nnz;
4056}
4057
4058/** gets the rank of the aggregation row */
4060 SCIP_AGGRROW* aggrrow /**< aggregation row */
4061 )
4062{
4063 assert(aggrrow != NULL);
4064
4065 return aggrrow->rank;
4066}
4067
4068/** checks if the aggregation row is only valid locally */
4070 SCIP_AGGRROW* aggrrow /**< aggregation row */
4071 )
4072{
4073 assert(aggrrow != NULL);
4074
4075 return aggrrow->local;
4076}
4077
4078/** gets the right hand side of the aggregation row */
4080 SCIP_AGGRROW* aggrrow /**< aggregation row */
4081 )
4082{
4083 assert(aggrrow != NULL);
4084
4085 return QUAD_TO_DBL(aggrrow->rhs);
4086}
4087
4088/* =========================================== c-MIR =========================================== */
4089
4090#define MAXCMIRSCALE 1e+6 /**< maximal scaling (scale/(1-f0)) allowed in c-MIR calculations */
4091
4092/* In order to derive cuts, we partition the variable array up in (not necessarily contiguous) sections.
4093 * The only requirement we place on these sections is that section i can only have variable bounds variables whose section
4094 * is strictly greater than i. This way, we can process the variable array in a 'linear' manner. */
4095
4096/* @todo maintain a DAG for used varbounds and use topological ordering instead, this would also allow
4097 * variable bounds on variables of the same section to be used */
4098
4099#define NSECTIONS 6
4100
4101typedef struct MIR_Data
4102{
4103 int totalnnz; /* The total number of nonzeros in all of the sections */
4104 int* secindices[NSECTIONS]; /* The indices of the variables belonging to the section */
4105 int secnnz[NSECTIONS]; /* The number of nonzero indices in the section */
4106
4107 SCIP_Bool isenfint[NSECTIONS];/**< Does the section have an integrality constraint? */
4108 SCIP_Bool isimplint[NSECTIONS];/**< Is the section implied integer variables? */
4109
4110 /* Settings for cut derivation, per section */
4111 int usevbds[NSECTIONS]; /**< Should variable bound substitution be done for this section? */
4112
4113 /* Problem data that we reuse often */
4114 SCIP_VAR** vars; /**< pointer to SCIPs variable array */
4115 int nvars; /**< total number of variables */
4116 int nbinvars; /**< total number of non-implint binary variables */
4117 int nintvars; /**< total number of non-implint integer variables */
4118 int nbinimplvars; /**< total number of implint binary variables */
4119 int nintimplvars; /**< total number of implint integer variables */
4120 int ncontimplvars; /**< total number of implint continuous variables */
4121 int ncontvars; /**< total number of non-implied continuous variables */
4122
4123 SCIP_Real* cutcoefs; /**< working cut indices value array */
4124 SCIP_Real QUAD(cutrhs); /**< the working right hand side of the cut*/
4125
4126 int* cutinds; /**< working cut variable problem index array */
4127 int ncutinds; /**< number of values in the working cut variable problem index array */
4129
4130/** Returns the section of a variable.
4131 *
4132 * For now, this is equal to the variable type section of the variable in the problem.
4133 */
4134static
4136 MIR_DATA* data, /**< The MIR separation data */
4137 int probindex /**< Problem index of a variable */
4138 )
4139{
4140 int limit;
4141
4142 assert(data != NULL);
4143
4144 limit = data->nvars - data->ncontvars;
4145 if( probindex >= limit )
4146 return 0;
4147
4148 limit -= data->ncontimplvars;
4149 if( probindex >= limit )
4150 return 1;
4151
4152 limit -= data->nintimplvars;
4153 if( probindex >= limit )
4154 return 2;
4155
4156 limit -= data->nbinimplvars;
4157 if( probindex >= limit )
4158 return 3;
4159
4160 limit -= data->nintvars;
4161 if( probindex >= limit )
4162 return 4;
4163
4164 assert(limit == data->nbinvars);
4165
4166 return 5;
4167}
4168
4169/** finds the best lower bound of the variable to use for MIR transformation.
4170 *
4171 * Currently, we use a slightly different function for the exact MIR cuts than for the normal MIR cuts due to differences
4172 * in how the codes can handle variable bound substitution. This function can only be used with the safe MIR code. */
4173/* @todo make behavior identical to the unsafe MIR cut computation */
4174static
4176 SCIP* scip, /**< SCIP data structure */
4177 SCIP_VAR* var, /**< problem variable */
4178 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4179 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4180 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4181 SCIP_Real* bestlb, /**< pointer to store best bound value */
4182 SCIP_Real* simplebound, /**< pointer to store simple bound value */
4183 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4184 )
4185{
4186 assert(bestlb != NULL);
4187 assert(bestlbtype != NULL);
4188 assert(usevbds >= 0 && usevbds <= 2);
4189
4190 *bestlb = SCIPvarGetLbGlobal(var);
4191 *bestlbtype = -1;
4192
4193 if( allowlocal )
4194 {
4195 SCIP_Real loclb;
4196
4197 loclb = SCIPvarGetLbLocal(var);
4198 if( SCIPisGT(scip, loclb, *bestlb) )
4199 {
4200 *bestlb = loclb;
4201 *bestlbtype = -2;
4202 }
4203 }
4204
4205 *simplebound = *bestlb;
4206
4207 if( usevbds && !SCIPvarIsIntegral(var) )
4208 {
4209 SCIP_Real bestvlb;
4210 int bestvlbidx;
4211
4212 SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
4213 if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
4214 {
4215 SCIP_VAR** vlbvars;
4216 SCIP_VAR* vlbvar;
4217
4218 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4219 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
4220 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
4221 */
4222 vlbvars = SCIPvarGetVlbVars(var);
4223 assert(vlbvars != NULL);
4224 vlbvar = vlbvars[bestvlbidx];
4225 assert(vlbvar != NULL);
4226 if( ( usevbds == 2 || ( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY
4227 && !SCIPvarIsImpliedIntegral(vlbvar) ) )
4229 {
4230 *bestlb = bestvlb;
4231 *bestlbtype = bestvlbidx;
4232 }
4233 }
4234 }
4235
4236 return SCIP_OKAY;
4237}
4238
4239/** finds the best upper bound of the variable to use for MIR transformation.
4240 * currently, we use a slightly different function for the exact MIR cuts than for the normal MIR cuts due to differences
4241 * in how the codes can handle variable bound substitution. This function can only be used with the safe MIR code. */
4242/* @todo make behavior identical to the unsafe MIR cut computation */
4243static
4245 SCIP* scip, /**< SCIP data structure */
4246 SCIP_VAR* var, /**< problem variable */
4247 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4248 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4249 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4250 SCIP_Real* bestub, /**< pointer to store best bound value */
4251 SCIP_Real* simplebound, /**< pointer to store simple bound */
4252 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4253 )
4254{
4255 assert(bestub != NULL);
4256 assert(bestubtype != NULL);
4257
4258 *bestub = SCIPvarGetUbGlobal(var);
4259 *bestubtype = -1;
4260
4261 if( allowlocal )
4262 {
4263 SCIP_Real locub;
4264
4265 locub = SCIPvarGetUbLocal(var);
4266 if( SCIPisLT(scip, locub, *bestub) )
4267 {
4268 *bestub = locub;
4269 *bestubtype = -2;
4270 }
4271 }
4272
4273 *simplebound = *bestub;
4274
4275 if( usevbds && !SCIPvarIsIntegral(var) )
4276 {
4277 SCIP_Real bestvub;
4278 int bestvubidx;
4279
4280 SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
4281 if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
4282 {
4283 SCIP_VAR** vubvars;
4284 SCIP_VAR* vubvar;
4285
4286 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4287 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
4288 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
4289 */
4290 vubvars = SCIPvarGetVubVars(var);
4291 assert(vubvars != NULL);
4292 vubvar = vubvars[bestvubidx];
4293 assert(vubvar != NULL);
4294 if( ( usevbds == 2 || ( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY
4295 && !SCIPvarIsImpliedIntegral(vubvar) ) )
4297 {
4298 *bestub = bestvub;
4299 *bestubtype = bestvubidx;
4300 }
4301 }
4302 }
4303
4304 return SCIP_OKAY;
4305}
4306
4307/** determine the best bounds with respect to the given solution for complementing the given variable */
4308/* @todo make behavior identical to the unsafe MIR cut computation */
4309static
4311 SCIP* scip, /**< SCIP data structure */
4312 SCIP_VAR* var, /**< variable to determine best bound for */
4313 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4314 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
4315 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4316 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4317 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
4318 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
4319 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
4320 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
4321 * NULL for using closest bound for all variables */
4322 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
4323 * NULL for using closest bound for all variables */
4324 SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
4325 SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
4326 int* bestlbtype, /**< pointer to store type of the best lower bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
4327 int* bestubtype, /**< pointer to store type of best upper bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
4328 SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
4329 SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
4330 )
4331{
4332 SCIP_Real simplelb;
4333 SCIP_Real simpleub;
4334 int v;
4335
4337
4338 /* check if the user specified a bound to be used */
4339 if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
4340 {
4341 assert(!SCIPvarIsIntegral(var) || boundsfortrans[v] == -2 || boundsfortrans[v] == -1);
4342 assert(boundtypesfortrans != NULL);
4343
4344 /* user has explicitly specified a bound to be used */
4345 if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
4346 {
4347 /* user wants to use lower bound */
4348 *bestlbtype = boundsfortrans[v];
4349 if( *bestlbtype == -1 )
4350 *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
4351 else if( *bestlbtype == -2 )
4352 *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
4353 else
4354 {
4355 SCIP_VAR** vlbvars;
4356 SCIP_Real* vlbcoefs;
4357 SCIP_Real* vlbconsts;
4358 int k;
4359
4360 assert(!ignoresol);
4361
4362 /* use the given variable lower bound */
4363 vlbvars = SCIPvarGetVlbVars(var);
4364 vlbcoefs = SCIPvarGetVlbCoefs(var);
4365 vlbconsts = SCIPvarGetVlbConstants(var);
4366 k = boundsfortrans[v];
4367 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
4368 assert(vlbvars != NULL);
4369 assert(vlbcoefs != NULL);
4370 assert(vlbconsts != NULL);
4371
4372 *bestlb = vlbcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[k]) : SCIPgetSolVal(scip, sol, vlbvars[k])) + vlbconsts[k];
4373 }
4374
4375 assert(!SCIPisInfinity(scip, - *bestlb));
4376 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4377
4378 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
4379 SCIP_CALL( findBestUbSafely(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
4380 }
4381 else
4382 {
4383 assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
4384
4385 /* user wants to use upper bound */
4386 *bestubtype = boundsfortrans[v];
4387 if( *bestubtype == -1 )
4388 *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
4389 else if( *bestubtype == -2 )
4390 *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
4391 else
4392 {
4393 SCIP_VAR** vubvars;
4394 SCIP_Real* vubcoefs;
4395 SCIP_Real* vubconsts;
4396 int k;
4397
4398 assert(!ignoresol);
4399
4400 /* use the given variable upper bound */
4401 vubvars = SCIPvarGetVubVars(var);
4402 vubcoefs = SCIPvarGetVubCoefs(var);
4403 vubconsts = SCIPvarGetVubConstants(var);
4404 k = boundsfortrans[v];
4405 assert(k >= 0 && k < SCIPvarGetNVubs(var));
4406 assert(vubvars != NULL);
4407 assert(vubcoefs != NULL);
4408 assert(vubconsts != NULL);
4409
4410 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4411 *bestub = vubcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vubvars[k]) : SCIPgetSolVal(scip, sol, vubvars[k])) + vubconsts[k];
4412 }
4413
4414 assert(!SCIPisInfinity(scip, *bestub));
4415 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4416
4417 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
4418 SCIP_CALL( findBestLbSafely(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
4419 }
4420 }
4421 else
4422 {
4423 SCIP_Real varsol;
4424
4425 /* bound selection should be done automatically */
4426
4427 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
4428 SCIP_CALL( findBestLbSafely(scip, var, sol, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
4429
4430 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
4431 SCIP_CALL( findBestUbSafely(scip, var, sol, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
4432
4433 /* check, if variable is free variable */
4434 if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
4435 {
4436 /* we found a free variable in the row with non-zero coefficient
4437 * -> MIR row can't be transformed in standard form
4438 */
4439 *freevariable = TRUE;
4440 return SCIP_OKAY;
4441 }
4442
4443 if( !ignoresol )
4444 {
4445 /* select transformation bound */
4446 varsol = (sol == NULL ? SCIPvarGetLPSol(var) : SCIPgetSolVal(scip, sol, var));
4447
4448 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
4449 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4450 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
4451 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4452 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
4453 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4454 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
4455 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4456 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
4457 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4458 else if( *bestubtype == -1 ) /* prefer global standard bounds */
4459 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4460 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
4461 {
4462 if( *bestlb - simplelb > simpleub - *bestub )
4463 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4464 else
4465 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4466 }
4467 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
4468 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4469 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
4470 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4471 else /* no decision yet? just use lower bound */
4472 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4473 }
4474 else
4475 {
4478 SCIP_Real distlb = REALABS(glblb - *bestlb);
4479 SCIP_Real distub = REALABS(glbub - *bestub);
4480
4481 assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
4482
4483 if( SCIPisInfinity(scip, - *bestlb) )
4484 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4485 else if( !SCIPisNegative(scip, *bestlb) )
4486 {
4487 if( SCIPisInfinity(scip, *bestub) )
4488 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4489 else if( SCIPisZero(scip, glblb) )
4490 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4491 else if( SCIPisLE(scip, distlb, distub) )
4492 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4493 else
4494 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4495 }
4496 else
4497 {
4498 assert(!SCIPisInfinity(scip, - *bestlb));
4499 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4500 }
4501 }
4502 }
4503
4504 return SCIP_OKAY; /*lint !e438*/
4505}
4506
4507/** finds the best lower bound of the variable to use for MIR transformation */
4508static
4510 SCIP* scip, /**< SCIP data structure */
4511 SCIP_VAR* var, /**< problem variable */
4512 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4513 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4514 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4515 SCIP_Real* bestlb, /**< pointer to store best bound value */
4516 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4517 )
4518{
4519 assert(bestlb != NULL);
4520 assert(bestlbtype != NULL);
4521 assert(usevbds >= 0 && usevbds <= 2);
4522
4523 *bestlb = SCIPvarGetLbGlobal(var);
4524 *bestlbtype = -1;
4525
4526 if( allowlocal )
4527 {
4528 SCIP_Real loclb;
4529
4530 loclb = SCIPvarGetLbLocal(var);
4531 if( SCIPisGT(scip, loclb, *bestlb) )
4532 {
4533 *bestlb = loclb;
4534 *bestlbtype = -2;
4535 }
4536 }
4537
4538 if( usevbds > 0 )
4539 {
4540 SCIP_Real bestvlb;
4541 int bestvlbidx;
4542
4543 SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
4544 if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
4545 {
4546 SCIP_VAR** vlbvars;
4547 SCIP_VAR* vlbvar;
4548
4549 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4550 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
4551 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
4552 */
4553 vlbvars = SCIPvarGetVlbVars(var);
4554 assert(vlbvars != NULL);
4555 vlbvar = vlbvars[bestvlbidx];
4556 assert(vlbvar != NULL);
4557 if( ( usevbds == 2 || ( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY
4558 && !SCIPvarIsImpliedIntegral(vlbvar) ) ) )
4559 {
4561 *bestlb = bestvlb;
4562 *bestlbtype = bestvlbidx;
4563 }
4564 }
4565 }
4566
4567 return SCIP_OKAY;
4568}
4569
4570/** finds the best upper bound of the variable to use for MIR transformation */
4571static
4573 SCIP* scip, /**< SCIP data structure */
4574 SCIP_VAR* var, /**< problem variable */
4575 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4576 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4577 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4578 SCIP_Real* bestub, /**< pointer to store best bound value */
4579 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4580 )
4581{
4582 assert(bestub != NULL);
4583 assert(bestubtype != NULL);
4584 assert(usevbds >= 0 && usevbds <= 2);
4585
4586 *bestub = SCIPvarGetUbGlobal(var);
4587 *bestubtype = -1;
4588
4589 if( allowlocal )
4590 {
4591 SCIP_Real locub;
4592
4593 locub = SCIPvarGetUbLocal(var);
4594 if( SCIPisLT(scip, locub, *bestub) )
4595 {
4596 *bestub = locub;
4597 *bestubtype = -2;
4598 }
4599 }
4600
4601 if( usevbds > 0 )
4602 {
4603 SCIP_Real bestvub;
4604 int bestvubidx;
4605
4606 SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
4607 if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
4608 {
4609 SCIP_VAR** vubvars;
4610 SCIP_VAR* vubvar;
4611
4612 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4613 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
4614 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
4615 */
4616 vubvars = SCIPvarGetVubVars(var);
4617 assert(vubvars != NULL);
4618 vubvar = vubvars[bestvubidx];
4619 assert(vubvar != NULL);
4620 if( ( usevbds == 2 || ( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY
4621 && !SCIPvarIsImpliedIntegral(vubvar) ) ) )
4622 {
4624 *bestub = bestvub;
4625 *bestubtype = bestvubidx;
4626 }
4627 }
4628 }
4629
4630 return SCIP_OKAY;
4631}
4632
4633
4634/** finds the best lower bound of the variable to use for MIR transformation.
4635 * Differs from findBestLB() in that it allows more variable bound substitutions based on the variable sections. */
4636static
4638 SCIP* scip, /**< SCIP data structure */
4639 SCIP_VAR* var, /**< problem variable */
4640 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4641 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
4642 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4643 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4644 SCIP_Real* bestlb, /**< pointer to store best bound value */
4645 SCIP_Real* simplebound, /**< pointer to store simple bound value */
4646 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4647 )
4648{
4649 assert(bestlb != NULL);
4650 assert(bestlbtype != NULL);
4651 assert(usevbds >= 0 && usevbds <= 2);
4652
4653 *bestlb = SCIPvarGetLbGlobal(var);
4654 *bestlbtype = -1;
4655
4656 if( allowlocal )
4657 {
4658 SCIP_Real loclb;
4659
4660 loclb = SCIPvarGetLbLocal(var);
4661 if( SCIPisGT(scip, loclb, *bestlb) )
4662 {
4663 *bestlb = loclb;
4664 *bestlbtype = -2;
4665 }
4666 }
4667
4668 *simplebound = *bestlb;
4669
4670 if( usevbds > 0 )
4671 {
4672 int nvlbs = SCIPvarGetNVlbs(var);
4673
4674 if( nvlbs > 0 )
4675 {
4676 SCIP_Real bestvlb = SCIP_REAL_MIN;
4677 int bestvlbtype = -1;
4678 int boundedsection = varSection(data, SCIPvarGetProbindex(var));
4679
4680 SCIP_VAR** vlbvars;
4681 SCIP_Real* vlbcoefs;
4682 SCIP_Real* vlbconsts;
4683 int i;
4684
4685 vlbvars = SCIPvarGetVlbVars(var);
4686 vlbcoefs = SCIPvarGetVlbCoefs(var);
4687 vlbconsts = SCIPvarGetVlbConstants(var);
4688
4689 /* search best VLB */
4690 for( i = 0; i < nvlbs; i++ )
4691 {
4692 /* For now, we only allow variable bounds from sections that are strictly greater to prevent cyclic usage.*/
4693 /** @todo: We don't use the caching mechanism of SCIPvarGetClosestVLB() because the cached variable bound
4694 * may be illegal. Building a local cache here may be worth it. */
4695 if( SCIPvarIsActive(vlbvars[i]) && boundedsection < varSection(data, SCIPvarGetProbindex(vlbvars[i])) &&
4696 (usevbds == 2 || SCIPvarIsBinary(vlbvars[i])) )
4697 {
4698 SCIP_Real vlbsol;
4699 SCIP_Real vlbbnd;
4700
4701 vlbsol = SCIPgetSolVal(scip, sol, vlbvars[i]);
4702 vlbbnd = vlbcoefs[i] * vlbsol + vlbconsts[i];
4703
4704 if( vlbbnd > bestvlb )
4705 {
4706 bestvlb = vlbbnd;
4707 bestvlbtype = i;
4708 }
4709 }
4710 }
4711
4712 if( bestvlbtype >= 0 && SCIPisGE(scip, bestvlb, *bestlb) )
4713 {
4714 *bestlb = bestvlb;
4715 *bestlbtype = bestvlbtype;
4716 }
4717 }
4718 }
4719
4720 return SCIP_OKAY;
4721}
4722
4723/** finds the best upper bound of the variable to use for MIR transformation.
4724 * Differs from findBestUB() in that it allows more variable bound substitutions based on the variable sections. */
4725static
4727 SCIP* scip, /**< SCIP data structure */
4728 SCIP_VAR* var, /**< problem variable */
4729 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4730 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
4731 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4732 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4733 SCIP_Real* bestub, /**< pointer to store best bound value */
4734 SCIP_Real* simplebound, /**< pointer to store simple bound */
4735 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4736 )
4737{
4738 assert(bestub != NULL);
4739 assert(bestubtype != NULL);
4740 assert(usevbds >= 0 && usevbds <= 2);
4741
4742 *bestub = SCIPvarGetUbGlobal(var);
4743 *bestubtype = -1;
4744
4745 if( allowlocal )
4746 {
4747 SCIP_Real locub;
4748
4749 locub = SCIPvarGetUbLocal(var);
4750 if( SCIPisLT(scip, locub, *bestub) )
4751 {
4752 *bestub = locub;
4753 *bestubtype = -2;
4754 }
4755 }
4756
4757 *simplebound = *bestub;
4758
4759 if( usevbds > 0 )
4760 {
4761 int nvubs = SCIPvarGetNVubs(var);
4762
4763 if( nvubs > 0 )
4764 {
4765 SCIP_Real bestvub = SCIP_REAL_MAX;
4766 int bestvubtype = -1;
4767 int boundedsection = varSection(data, SCIPvarGetProbindex(var));
4768
4769 SCIP_VAR** vubvars;
4770 SCIP_Real* vubcoefs;
4771 SCIP_Real* vubconsts;
4772 int i;
4773
4774 vubvars = SCIPvarGetVubVars(var);
4775 vubcoefs = SCIPvarGetVubCoefs(var);
4776 vubconsts = SCIPvarGetVubConstants(var);
4777
4778 /* search best VUB */
4779 for( i = 0; i < nvubs; i++ )
4780 {
4781 /* For now, we only allow variable bounds from sections that are strictly greater to prevent cyclic usage.*/
4782 /** @todo: We don't use the caching mechanism of SCIPvarGetClosestVLB() because the cached variable bound
4783 * may be illegal. Building a local cache here may be worth it. */
4784 if( SCIPvarIsActive(vubvars[i]) && boundedsection < varSection(data, SCIPvarGetProbindex(vubvars[i])) &&
4785 (usevbds == 2 || SCIPvarIsBinary(vubvars[i])) )
4786 {
4787 SCIP_Real vubsol;
4788 SCIP_Real vubbnd;
4789
4790 vubsol = SCIPgetSolVal(scip, sol, vubvars[i]);
4791 vubbnd = vubcoefs[i] * vubsol + vubconsts[i];
4792
4793 if( vubbnd < bestvub )
4794 {
4795 bestvub = vubbnd;
4796 bestvubtype = i;
4797 }
4798 }
4799 }
4800
4801 if( bestvubtype >= 0 && SCIPisLE(scip, bestvub, *bestub) )
4802 {
4803 *bestub = bestvub;
4804 *bestubtype = bestvubtype;
4805 }
4806 }
4807 }
4808
4809 return SCIP_OKAY;
4810}
4811
4812/** determine the best bounds with respect to the given solution for complementing the given variable */
4813static
4815 SCIP* scip, /**< SCIP data structure */
4816 SCIP_VAR* var, /**< variable to determine best bound for */
4817 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4818 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
4819 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
4820 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4821 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4822 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
4823 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
4824 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
4825 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
4826 * NULL for using closest bound for all variables */
4827 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
4828 * NULL for using closest bound for all variables */
4829 SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
4830 SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
4831 int* bestlbtype, /**< pointer to store type of best lower bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
4832 int* bestubtype, /**< pointer to store type of best upper bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
4833 SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
4834 SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
4835 )
4836{
4837 SCIP_Real simplelb;
4838 SCIP_Real simpleub;
4839 int v;
4840
4841 assert(usevbds >= 0 && usevbds <= 2);
4842
4844
4845 /* check if the user specified a bound to be used */
4846 if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
4847 {
4848 assert(!SCIPvarIsIntegral(var) || boundsfortrans[v] == -2 || boundsfortrans[v] == -1);
4849 assert(boundtypesfortrans != NULL);
4850
4851 /* user has explicitly specified a bound to be used */
4852 if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
4853 {
4854 /* user wants to use lower bound */
4855 *bestlbtype = boundsfortrans[v];
4856 if( *bestlbtype == -1 )
4857 *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
4858 else if( *bestlbtype == -2 )
4859 *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
4860 else
4861 {
4862 SCIP_Real vlbsol;
4863 SCIP_VAR** vlbvars;
4864 SCIP_Real* vlbcoefs;
4865 SCIP_Real* vlbconsts;
4866 int k;
4867
4868 assert(!ignoresol);
4869
4870 /* use the given variable lower bound */
4871 vlbvars = SCIPvarGetVlbVars(var);
4872 vlbcoefs = SCIPvarGetVlbCoefs(var);
4873 vlbconsts = SCIPvarGetVlbConstants(var);
4874 k = boundsfortrans[v];
4875 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
4876 assert(vlbvars != NULL);
4877 assert(vlbcoefs != NULL);
4878 assert(vlbconsts != NULL);
4879
4880 vlbsol = SCIPgetSolVal(scip, sol, vlbvars[k]);
4881
4882 *bestlb = vlbcoefs[k] * vlbsol + vlbconsts[k];
4883 }
4884
4885 assert(!SCIPisInfinity(scip, - *bestlb));
4886 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4887
4888 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
4889 SCIP_CALL( findMIRBestUb(scip, var, sol, data, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
4890 }
4891 else
4892 {
4893 assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
4894
4895 /* user wants to use upper bound */
4896 *bestubtype = boundsfortrans[v];
4897 if( *bestubtype == -1 )
4898 *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
4899 else if( *bestubtype == -2 )
4900 *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
4901 else
4902 {
4903 SCIP_Real vubsol;
4904 SCIP_VAR** vubvars;
4905 SCIP_Real* vubcoefs;
4906 SCIP_Real* vubconsts;
4907 int k;
4908
4909 assert(!ignoresol);
4910
4911 /* use the given variable upper bound */
4912 vubvars = SCIPvarGetVubVars(var);
4913 vubcoefs = SCIPvarGetVubCoefs(var);
4914 vubconsts = SCIPvarGetVubConstants(var);
4915 k = boundsfortrans[v];
4916 assert(k >= 0 && k < SCIPvarGetNVubs(var));
4917 assert(vubvars != NULL);
4918 assert(vubcoefs != NULL);
4919 assert(vubconsts != NULL);
4920
4921 vubsol = SCIPgetSolVal(scip, sol, vubvars[k]);
4922 *bestub = vubcoefs[k] * vubsol + vubconsts[k];
4923 }
4924
4925 assert(!SCIPisInfinity(scip, *bestub));
4926 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4927
4928 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
4929 SCIP_CALL( findMIRBestLb(scip, var, sol, data, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
4930 }
4931 }
4932 else
4933 {
4934 SCIP_Real varsol;
4935
4936 /* bound selection should be done automatically */
4937
4938 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
4939 SCIP_CALL( findMIRBestLb(scip, var, sol, data, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
4940
4941 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
4942 SCIP_CALL( findMIRBestUb(scip, var, sol, data, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
4943
4944 /* check, if variable is free variable */
4945 if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
4946 {
4947 /* we found a free variable in the row with non-zero coefficient
4948 * -> MIR row can't be transformed in standard form
4949 */
4950 *freevariable = TRUE;
4951 return SCIP_OKAY;
4952 }
4953
4954 if( !ignoresol )
4955 {
4956 /* select transformation bound */
4957 varsol = SCIPgetSolVal(scip, sol, var);
4958
4959 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
4960 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4961 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
4962 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4963 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
4964 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4965 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
4966 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4967 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
4968 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4969 else if( *bestubtype == -1 ) /* prefer global standard bounds */
4970 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4971 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
4972 {
4973 if( *bestlb - simplelb > simpleub - *bestub )
4974 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4975 else
4976 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4977 }
4978 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
4979 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4980 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
4981 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4982 else /* no decision yet? just use lower bound */
4983 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4984 }
4985 else
4986 {
4989 SCIP_Real distlb = REALABS(glblb - *bestlb);
4990 SCIP_Real distub = REALABS(glbub - *bestub);
4991
4992 assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
4993
4994 if( SCIPisInfinity(scip, - *bestlb) )
4995 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4996 else if( !SCIPisNegative(scip, *bestlb) )
4997 {
4998 if( SCIPisInfinity(scip, *bestub) )
4999 *selectedbound = SCIP_BOUNDTYPE_LOWER;
5000 else if( SCIPisZero(scip, glblb) )
5001 *selectedbound = SCIP_BOUNDTYPE_LOWER;
5002 else if( SCIPisLE(scip, distlb, distub) )
5003 *selectedbound = SCIP_BOUNDTYPE_LOWER;
5004 else
5005 *selectedbound = SCIP_BOUNDTYPE_UPPER;
5006 }
5007 else
5008 {
5009 assert(!SCIPisInfinity(scip, - *bestlb));
5010 *selectedbound = SCIP_BOUNDTYPE_LOWER;
5011 }
5012 }
5013 }
5014
5015 return SCIP_OKAY; /*lint !e438*/
5016}
5017
5018/** Performs bound substitution for a MIR cut */
5019static
5021 SCIP* scip, /**< SCIP datastructure */
5022 MIR_DATA* data, /**< the MIR data structure for this cut */
5023 int varsign, /**< stores the sign of the transformed variable in summation */
5024 int boundtype, /**< stores the bound used for transformed variable:
5025 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5026 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5027 int probindex, /**< problem index of variable to perform the substitution step for */
5028 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5029 )
5030{
5031 SCIP_Real QUAD(coef);
5032 SCIP_Real QUAD(tmp);
5033
5034 assert(!SCIPisInfinity(scip, -varsign * boundval));
5035
5036 QUAD_ARRAY_LOAD(coef, data->cutcoefs, probindex);
5037
5038 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
5039 if( boundtype < 0 )
5040 {
5041 SCIPquadprecProdQD(tmp, coef, boundval);
5042 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, -tmp);
5043 *localbdsused = *localbdsused || ( boundtype == -2 );
5044 }
5045 else
5046 {
5047 SCIP_VAR** vbdvars;
5048 SCIP_Real* vbdcoefs;
5049 SCIP_Real* vbdconsts;
5050 SCIP_Real QUAD(zcoef);
5051 int zidx;
5052 SCIP_VAR* var = SCIPgetVars(scip)[probindex];
5053
5054 if( varsign == +1 )
5055 {
5056 vbdvars = SCIPvarGetVlbVars(var);
5057 vbdcoefs = SCIPvarGetVlbCoefs(var);
5058 vbdconsts = SCIPvarGetVlbConstants(var);
5059 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
5060 }
5061 else
5062 {
5063 vbdvars = SCIPvarGetVubVars(var);
5064 vbdcoefs = SCIPvarGetVubCoefs(var);
5065 vbdconsts = SCIPvarGetVubConstants(var);
5066 assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
5067 }
5068
5069 assert(vbdvars != NULL);
5070 assert(vbdcoefs != NULL);
5071 assert(vbdconsts != NULL);
5072 assert(SCIPvarIsActive(vbdvars[boundtype]));
5073
5074 zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
5075
5076 SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
5077 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, -tmp);
5078
5079 /* check if integral variable already exists in the row */
5080 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
5081
5082 /* If it is new, add it to the indices */
5083 if( QUAD_HI(zcoef) == 0.0 )
5084 {
5085 int section = varSection(data, zidx);
5086 assert(section > varSection(data, probindex));
5087
5088 data->secindices[section][data->secnnz[section]] = zidx;
5089 ++data->secnnz[section];
5090 ++data->totalnnz;
5091 }
5092
5093 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
5094 SCIPquadprecSumQQ(zcoef, zcoef, tmp);
5095
5096 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
5097 assert(QUAD_HI(zcoef) != 0.0);
5098
5099 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
5100 }
5101}
5102
5103/** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index
5104 *
5105 * @note this method is safe for usage in exact solving mode
5106 *
5107 * @todo make behavior identical to the unsafe MIR cut computation
5108 */
5109static
5111 SCIP* scip, /**< SCIP datastructure */
5112 SCIP_Real* cutcoefs, /**< array of cut coefficients */
5113 SCIP_Real* cutrhs, /**< pointer to right hand side of the cut */
5114 int varsign, /**< stores the sign of the transformed variable in summation */
5115 int boundtype, /**< stores the bound used for transformed variable:
5116 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5117 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5118 int probindex, /**< problem index of variable to perform the substitution step for */
5119 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5120 )
5121{
5122 SCIP_Real coef;
5123 SCIP_ROUNDMODE previousroundmode;
5124
5125 assert(!SCIPisInfinity(scip, -varsign * boundval));
5127
5128 previousroundmode = SCIPintervalGetRoundingMode();
5130
5131 coef = cutcoefs[probindex];
5132
5133 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
5134 if( boundtype < 0 )
5135 {
5136 *cutrhs += coef * (-boundval);
5137 *localbdsused = *localbdsused || (boundtype == -2);
5138 }
5139 else
5140 {
5141 /* we don't support vlbs in exact mode yet */
5143 SCIPerrorMessage("variable lower bounds not implemented in exact solving mode yet \n");
5144 SCIPABORT();
5145 }
5146
5147 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
5148}
5149
5150/** performs the bound substitution step with the simple bound for the variable with the given problem index
5151 *
5152 * @note this method is safe for usage in exact solving mode
5153 *
5154 * @todo make behavior identical to the unsafe MIR cut computation
5155 */
5156static
5158 SCIP* scip, /**< SCIP datastructure */
5159 SCIP_Real* cutcoefs, /**< array of cut coefficients */
5160 SCIP_Real* cutrhs, /**< pointer to right hand side of the cut */
5161 int boundtype, /**< stores the bound used for transformed variable:
5162 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5163 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5164 int probindex, /**< problem index of variable to perform the substitution step for */
5165 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5166 )
5167{
5168 SCIP_Real coef;
5169 SCIP_ROUNDMODE previousroundmode;
5170
5171 assert(!SCIPisInfinity(scip, ABS(boundval)));
5173
5174 previousroundmode = SCIPintervalGetRoundingMode();
5176
5177 coef = cutcoefs[probindex];
5178
5179 /* must be a standard bound */
5180 assert( boundtype < 0 );
5181
5182 *cutrhs += coef * (-boundval);
5183
5184 *localbdsused = *localbdsused || (boundtype == -2);
5185
5186 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
5187}
5188
5189/** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index */
5190static
5192 SCIP* scip, /**< SCIP datastructure */
5193 int* cutinds, /**< index array of nonzeros in the cut */
5194 SCIP_Real* cutcoefs, /**< array of cut coefficients */
5195 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
5196 int* nnz, /**< pointer to number of nonzeros of the cut */
5197 int varsign, /**< stores the sign of the transformed variable in summation */
5198 int boundtype, /**< stores the bound used for transformed variable:
5199 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5200 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5201 int probindex, /**< problem index of variable to perform the substitution step for */
5202 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5203 )
5204{
5205 SCIP_Real QUAD(coef);
5206 SCIP_Real QUAD(tmp);
5207
5208 assert(!SCIPisInfinity(scip, -varsign * boundval));
5210
5211 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
5212
5213 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
5214 if( boundtype < 0 )
5215 {
5216 SCIPquadprecProdQD(tmp, coef, boundval);
5217 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
5218 *localbdsused = *localbdsused || (boundtype == -2);
5219 }
5220 else
5221 {
5222 SCIP_VAR** vbdvars;
5223 SCIP_Real* vbdcoefs;
5224 SCIP_Real* vbdconsts;
5225 SCIP_Real QUAD(zcoef);
5226 int zidx;
5227 SCIP_VAR* var = SCIPgetVars(scip)[probindex];
5228
5229 if( varsign == +1 )
5230 {
5231 vbdvars = SCIPvarGetVlbVars(var);
5232 vbdcoefs = SCIPvarGetVlbCoefs(var);
5233 vbdconsts = SCIPvarGetVlbConstants(var);
5234 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
5235 }
5236 else
5237 {
5238 vbdvars = SCIPvarGetVubVars(var);
5239 vbdcoefs = SCIPvarGetVubCoefs(var);
5240 vbdconsts = SCIPvarGetVubConstants(var);
5241 assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
5242 }
5243
5244 assert(vbdvars != NULL);
5245 assert(vbdcoefs != NULL);
5246 assert(vbdconsts != NULL);
5247 assert(SCIPvarIsActive(vbdvars[boundtype]));
5248
5249 zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
5250
5251 SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
5252 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
5253
5254 /* check if integral variable already exists in the row */
5255 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
5256
5257 if( QUAD_HI(zcoef) == 0.0 )
5258 cutinds[(*nnz)++] = zidx;
5259
5260 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
5261 SCIPquadprecSumQQ(zcoef, zcoef, tmp);
5262
5263 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
5264 assert(QUAD_HI(zcoef) != 0.0);
5265
5266 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
5267 }
5268}
5269
5270/** performs the bound substitution step with the simple bound for the variable with the given problem index */
5271static
5273 SCIP* scip, /**< SCIP datastructure */
5274 SCIP_Real* cutcoefs, /**< array of cut coefficients */
5275 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
5276 int boundtype, /**< stores the bound used for transformed variable:
5277 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5278 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5279 int probindex, /**< problem index of variable to perform the substitution step for */
5280 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5281 )
5282{
5283 SCIP_Real QUAD(coef);
5284 SCIP_Real QUAD(tmp);
5285
5286 assert(!SCIPisInfinity(scip, ABS(boundval)));
5288
5289 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
5290
5291 /* must be a standard bound */
5292 assert( boundtype < 0 );
5293
5294 SCIPquadprecProdQD(tmp, coef, boundval);
5295 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
5296 *localbdsused = *localbdsused || (boundtype == -2);
5297}
5298
5299/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
5300 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
5301 *
5302 * Transform variables (lb or ub):
5303 * \f[
5304 * \begin{array}{llll}
5305 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \mbox{if lb is used in transformation},\\
5306 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if ub is used in transformation},
5307 * \end{array}
5308 * \f]
5309 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
5310 *
5311 * Transform variables (vlb or vub):
5312 * \f[
5313 * \begin{array}{llll}
5314 * x^\prime_j := x_j - (bl_j\, zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \mbox{if vlb is used in transf.} \\
5315 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if vub is used in transf.}
5316 * \end{array}
5317 * \f]
5318 * move the constant terms \f$ a_j\, dl_j \f$ or \f$ a_j\, du_j \f$ to the rhs, and update the coefficient of the VLB variable:
5319 * \f[
5320 * \begin{array}{ll}
5321 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
5322 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
5323 * \end{array}
5324 * \f]
5325 *
5326 * @note this method is safe for usage in exact solving mode
5327 *
5328 * @todo make behavior identical to the unsafe MIR cut computation
5329 */
5330static
5332 SCIP* scip, /**< SCIP data structure */
5333 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
5334 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5335 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
5336 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5337 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
5338 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
5339 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
5340 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
5341 * NULL for using closest bound for all variables */
5342 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
5343 * NULL for using closest bound for all variables */
5344 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
5345 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
5346 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
5347 int* nnz, /**< number of non-zeros in cut */
5348 int* varsign, /**< stores the sign of the transformed variable in summation */
5349 int* boundtype, /**< stores the bound used for transformed variable:
5350 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5351 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
5352 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
5353 )
5354{ /*lint --e{644}*/
5355 SCIP_Real* bestlbs;
5356 SCIP_Real* bestubs;
5357 int* bestlbtypes;
5358 int* bestubtypes;
5359 SCIP_BOUNDTYPE* selectedbounds;
5360 int i;
5361 int aggrrowintstart;
5362 int nvars;
5363 int firstcontvar;
5364 SCIP_VAR** vars;
5365 SCIP_MIRINFO* mirinfo = NULL;
5366
5367 SCIP_ROUNDMODE previousroundmode;
5368
5369 assert(varsign != NULL);
5370 assert(boundtype != NULL);
5371 assert(freevariable != NULL);
5372 assert(localbdsused != NULL);
5374
5375 if( SCIPisCertified(scip) )
5377 previousroundmode = SCIPintervalGetRoundingMode();
5379
5380 *freevariable = FALSE;
5381 *localbdsused = FALSE;
5382
5383 /* allocate temporary memory to store best bounds and bound types */
5384 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*(*nnz)) );
5385 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*(*nnz)) );
5386 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*(*nnz)) );
5387 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*(*nnz)) );
5388 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*(*nnz)) );
5389
5390 /* start with continuous variables, because using variable bounds can affect the untransformed integral
5391 * variables, and these changes have to be incorporated in the transformation of the integral variables
5392 * (continuous variables have largest problem indices!)
5393 */
5394 SCIPsortDownInt(cutinds, *nnz);
5395
5398 firstcontvar = nvars - SCIPgetNContVars(scip);
5399
5400 /* determine the best bounds for the continuous variables */
5401 for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
5402 {
5403 SCIP_CALL( determineBestBoundsSafely(scip, vars[cutinds[i]], sol, boundswitch, usevbds ? 2 : 0, allowlocal, fixintegralrhs,
5404 ignoresol, boundsfortrans, boundtypesfortrans,
5405 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
5406
5407 if( *freevariable )
5408 goto TERMINATE;
5409 }
5410
5411 /* remember start of integer variables in the aggrrow */
5412 aggrrowintstart = i;
5413
5414 /* perform bound substitution for continuous variables */
5415 for( i = 0; i < aggrrowintstart; ++i )
5416 {
5417 int v = cutinds[i];
5418
5419 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5420 {
5421 assert(!SCIPisInfinity(scip, -bestlbs[i]));
5422
5423 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
5424 boundtype[i] = bestlbtypes[i];
5425 varsign[i] = +1;
5426
5427 performBoundSubstitutionSafely(scip, cutcoefs, cutrhs, varsign[i], boundtype[i], bestlbs[i], v, localbdsused);
5428 }
5429 else
5430 {
5431 assert(!SCIPisInfinity(scip, bestubs[i]));
5432
5433 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
5434 boundtype[i] = bestubtypes[i];
5435 varsign[i] = -1;
5436
5437 performBoundSubstitutionSafely(scip, cutcoefs, cutrhs, varsign[i], boundtype[i], bestubs[i], v, localbdsused);
5438 }
5439
5440 if( SCIPisCertified(scip) )
5441 {
5442 assert(mirinfo != NULL);
5443 if( boundtype[i] == -2 )
5444 {
5445 mirinfo->localbdused[v] = TRUE;
5446 mirinfo->nlocalvars++;
5447 }
5448 mirinfo->upperused[v] = (varsign[i] == -1);
5449 }
5450 }
5451
5452 /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
5453 * and determine the bound to use for the integer variables that are left
5454 */
5455 while( i < *nnz )
5456 {
5457 int v = cutinds[i];
5458 assert(cutinds[i] < firstcontvar);
5459
5460 /* determine the best bounds for the integral variable, usevbd can be set to 0 here as vbds are only used for continuous variables */
5461 SCIP_CALL( determineBestBoundsSafely(scip, vars[v], sol, boundswitch, 0, allowlocal, fixintegralrhs,
5462 ignoresol, boundsfortrans, boundtypesfortrans,
5463 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
5464
5465 /* increase i */
5466 ++i;
5467
5468 if( *freevariable )
5469 goto TERMINATE;
5470 }
5471
5472 /* now perform the bound substitution on the remaining integral variables which only uses standard bounds */
5473 for( i = aggrrowintstart; i < *nnz; ++i )
5474 {
5475 int v = cutinds[i];
5476
5477 /* perform bound substitution */
5478 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5479 {
5480 assert(!SCIPisInfinity(scip, - bestlbs[i]));
5481 assert(bestlbtypes[i] < 0);
5482
5483 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
5484 boundtype[i] = bestlbtypes[i];
5485 varsign[i] = +1;
5486
5487 performBoundSubstitutionSimpleSafely(scip, cutcoefs, cutrhs, boundtype[i], bestlbs[i], v, localbdsused);
5488 }
5489 else
5490 {
5491 assert(!SCIPisInfinity(scip, bestubs[i]));
5492 assert(bestubtypes[i] < 0);
5493
5494 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
5495 boundtype[i] = bestubtypes[i];
5496 varsign[i] = -1;
5497
5498 performBoundSubstitutionSimpleSafely(scip, cutcoefs, cutrhs, boundtype[i], bestubs[i], v, localbdsused);
5499 }
5500
5501 if( SCIPisCertified(scip) )
5502 {
5503 assert(mirinfo != NULL);
5504 if( boundtype[i] == -2 )
5505 {
5506 mirinfo->localbdused[v] = TRUE;
5507 mirinfo->nlocalvars++;
5508 }
5509 mirinfo->upperused[v] = (varsign[i] == -1);
5510 }
5511 }
5512
5513 TERMINATE:
5514 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
5515
5516 /*free temporary memory */
5517 SCIPfreeBufferArray(scip, &selectedbounds);
5518 SCIPfreeBufferArray(scip, &bestubtypes);
5519 SCIPfreeBufferArray(scip, &bestlbtypes);
5520 SCIPfreeBufferArray(scip, &bestubs);
5521 SCIPfreeBufferArray(scip, &bestlbs);
5522
5523 return SCIP_OKAY;
5524}
5525
5526/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
5527 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
5528 *
5529 * Transform variables (lb or ub):
5530 * \f[
5531 * \begin{array}{llll}
5532 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \mbox{if lb is used in transformation},\\
5533 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if ub is used in transformation},
5534 * \end{array}
5535 * \f]
5536 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
5537 *
5538 * Transform variables (vlb or vub):
5539 * \f[
5540 * \begin{array}{llll}
5541 * x^\prime_j := x_j - (bl_j\, zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \mbox{if vlb is used in transf.} \\
5542 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if vub is used in transf.}
5543 * \end{array}
5544 * \f]
5545 * move the constant terms \f$ a_j\, dl_j \f$ or \f$ a_j\, du_j \f$ to the rhs, and update the coefficient of the VLB variable:
5546 * \f[
5547 * \begin{array}{ll}
5548 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
5549 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
5550 * \end{array}
5551 * \f]
5552 */
5553static
5555 SCIP* scip, /**< SCIP datastructure */
5556 MIR_DATA* data, /**< the MIR data structure for this cut */
5557 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
5558 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5559 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5560 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
5561 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
5562 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
5563 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
5564 * NULL for using closest bound for all variables */
5565 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
5566 * NULL for using closest bound for all variables */
5567 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
5568 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
5569 int* varsign, /**< stores the sign of the transformed variable in summation */
5570 int* boundtype, /**< stores the bound used for transformed variable:
5571 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5572 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
5573 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
5574 )
5575{
5576 SCIP_Real* bestlbs;
5577 SCIP_Real* bestubs;
5578 int* bestlbtypes;
5579 int* bestubtypes;
5580 SCIP_BOUNDTYPE* selectedbounds;
5581 SCIP_Real QUAD(coef);
5582 int totalnnz;
5583 int s;
5584 int i;
5585
5586 assert(data != NULL);
5587 assert(varsign != NULL);
5588 assert(boundtype != NULL);
5589 assert(freevariable != NULL);
5590 assert(localbdsused != NULL);
5591
5592 totalnnz = data->totalnnz;
5593
5594 *freevariable = FALSE;
5595 *localbdsused = FALSE;
5596
5597 int allocsize = MIN(NSECTIONS * totalnnz, data->nvars);
5598 /* allocate temporary memory to store best bounds and bound types */
5599 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, allocsize) );
5600 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, allocsize) );
5601 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, allocsize) );
5602 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, allocsize) );
5603 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, allocsize) );
5604
5605 /* transform the cut, one variable section at a time */
5606 for( s = 0; s < NSECTIONS; ++s )
5607 {
5608 int* indices = data->secindices[s];
5609 int cutindsstart = data->ncutinds;
5610 int usevbds = data->usevbds[s];
5611
5612 i = 0;
5613 while( i < data->secnnz[s] )
5614 {
5615 int cutindex;
5616 int v = indices[i];
5617
5618 /* due to variable bound usage, cancellation may have occurred */
5619 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
5620 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
5621 {
5622 QUAD_ASSIGN(coef, 0.0);
5623 QUAD_ARRAY_STORE(data->cutcoefs, v, coef);
5624 --data->secnnz[s];
5625 --data->totalnnz;
5626 indices[i] = indices[data->secnnz[s]];
5627 /* do not increase the index */
5628 continue;
5629 }
5630
5631 cutindex = data->ncutinds;
5632 assert(cutindex < allocsize);
5633 SCIP_CALL( determineBestBounds(scip, data->vars[v], sol, data, boundswitch, usevbds, allowlocal, fixintegralrhs,
5634 ignoresol, boundsfortrans, boundtypesfortrans,
5635 bestlbs + cutindex, bestubs + cutindex, bestlbtypes + cutindex, bestubtypes + cutindex,
5636 selectedbounds + cutindex, freevariable) );
5637
5638 data->cutinds[cutindex] = v;
5639 ++data->ncutinds;
5640
5641 ++i;
5642
5643 /* if there is a free variable, we terminate because we cannot derive a MIR cut */
5644 if( *freevariable )
5645 {
5646 int j;
5647 int k;
5648
5649 data->ncutinds = 0;
5650
5651 /* if we terminate early, we need to make sure all the zeros in the cut coefficient array are cancelled */
5652 for( j = 0; j < NSECTIONS; ++j )
5653 {
5654 int* indexlist = data->secindices[j];
5655 for( k = 0; k < data->secnnz[j]; ++k )
5656 {
5657 data->cutinds[data->ncutinds] = indexlist[k];
5658 ++data->ncutinds;
5659 }
5660 }
5661 goto TERMINATE;
5662 }
5663 }
5664
5665 /* perform bound substitution for added variables */
5666 for( i = cutindsstart; i < data->ncutinds; ++i )
5667 {
5668 SCIP_Real bestbnd;
5669 int v = data->cutinds[i];
5670
5671 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5672 {
5673 assert(!SCIPisInfinity(scip, -bestlbs[i]));
5674
5675 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
5676 boundtype[i] = bestlbtypes[i];
5677 varsign[i] = +1;
5678 bestbnd = bestlbs[i];
5679 }
5680 else
5681 {
5682 assert(!SCIPisInfinity(scip, bestubs[i]));
5683
5684 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
5685 boundtype[i] = bestubtypes[i];
5686 varsign[i] = -1;
5687 bestbnd = bestubs[i];
5688 }
5689 doMIRBoundSubstitution(scip, data, varsign[i], boundtype[i], bestbnd, v, localbdsused);
5690 }
5691 }
5692
5693 if( fixintegralrhs )
5694 {
5695 SCIP_Real f0;
5696
5697 /* check if rhs is fractional */
5698 f0 = EPSFRAC(QUAD_TO_DBL(data->cutrhs), SCIPsumepsilon(scip));
5699 if( f0 < minfrac || f0 > maxfrac )
5700 {
5701 SCIP_Real bestviolgain;
5702 SCIP_Real bestnewf0;
5703 int besti;
5704
5705 /* choose complementation of one variable differently such that f0 is in correct range */
5706 besti = -1;
5707 bestviolgain = -1e+100;
5708 bestnewf0 = 1.0;
5709 for( i = 0; i < data->ncutinds; i++ )
5710 {
5711 int v;
5712
5713 v = data->cutinds[i];
5714 assert(0 <= v && v < data->nvars);
5715
5716 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
5718
5719 if( boundtype[i] < 0
5720 && ((varsign[i] == +1 && !SCIPisInfinity(scip, bestubs[i]) && bestubtypes[i] < 0)
5721 || (varsign[i] == -1 && !SCIPisInfinity(scip, -bestlbs[i]) && bestlbtypes[i] < 0)) )
5722 {
5723 SCIP_Real fj;
5724 SCIP_Real newfj;
5725 SCIP_Real newrhs;
5726 SCIP_Real newf0;
5727 SCIP_Real solval;
5728 SCIP_Real viol;
5729 SCIP_Real newviol;
5730 SCIP_Real violgain;
5731
5732 /* currently: a'_j = varsign * a_j -> f'_j = a'_j - floor(a'_j)
5733 * after complementation: a''_j = -varsign * a_j -> f''_j = a''_j - floor(a''_j) = 1 - f'_j
5734 * rhs'' = rhs' + varsign * a_j * (lb_j - ub_j)
5735 * cut violation from f0 and fj: f'_0 - f'_j * x'_j
5736 * after complementation: f''_0 - f''_j * x''_j
5737 *
5738 * for continuous variables, we just set f'_j = f''_j = |a'_j|
5739 */
5740 newrhs = QUAD_TO_DBL(data->cutrhs) + varsign[i] * QUAD_TO_DBL(coef) * (bestlbs[i] - bestubs[i]);
5741 newf0 = EPSFRAC(newrhs, SCIPsumepsilon(scip));
5742
5743 if( newf0 < minfrac || newf0 > maxfrac )
5744 continue;
5745 if( v >= data->nvars - data->ncontvars )
5746 {
5747 fj = REALABS(QUAD_TO_DBL(coef));
5748 newfj = fj;
5749 }
5750 else
5751 {
5752 fj = SCIPfrac(scip, varsign[i] * QUAD_TO_DBL(coef));
5753 newfj = SCIPfrac(scip, -varsign[i] * QUAD_TO_DBL(coef));
5754 }
5755
5756 if( !ignoresol )
5757 {
5758 solval = SCIPgetSolVal(scip, sol, data->vars[v]);
5759 viol = f0 - fj * (varsign[i] == +1 ? solval - bestlbs[i] : bestubs[i] - solval);
5760 newviol = newf0 - newfj * (varsign[i] == -1 ? solval - bestlbs[i] : bestubs[i] - solval);
5761 violgain = newviol - viol;
5762 }
5763 else
5764 {
5765 /* todo: this should be done, this can improve the dualray significantly */
5766 SCIPerrorMessage("Cannot handle closest bounds with ignoring the LP solution.\n");
5767 return SCIP_INVALIDCALL;
5768 }
5769
5770 /* prefer larger violations; for equal violations, prefer smaller f0 values since then the possibility that
5771 * we f_j > f_0 is larger and we may improve some coefficients in rounding
5772 */
5773 if( SCIPisGT(scip, violgain, bestviolgain) || (SCIPisGE(scip, violgain, bestviolgain) && newf0 < bestnewf0) )
5774 {
5775 besti = i;
5776 bestviolgain = violgain;
5777 bestnewf0 = newf0;
5778 }
5779 }
5780 }
5781
5782 if( besti >= 0 )
5783 {
5784 SCIP_Real QUAD(tmp);
5785
5786 assert(besti < data->ncutinds);
5787 assert(boundtype[besti] < 0);
5788 assert(!SCIPisInfinity(scip, -bestlbs[besti]));
5789 assert(!SCIPisInfinity(scip, bestubs[besti]));
5790
5791 QUAD_ARRAY_LOAD(coef, data->cutcoefs, data->cutinds[besti]);
5792 QUAD_SCALE(coef, varsign[besti]);
5793
5794 /* switch the complementation of this variable */
5795 SCIPquadprecSumDD(tmp, bestlbs[besti], - bestubs[besti]);
5796 SCIPquadprecProdQQ(tmp, tmp, coef);
5797 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
5798
5799 if( varsign[besti] == +1 )
5800 {
5801 /* switch to upper bound */
5802 assert(bestubtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
5803 boundtype[besti] = bestubtypes[besti];
5804 varsign[besti] = -1;
5805 }
5806 else
5807 {
5808 /* switch to lower bound */
5809 assert(bestlbtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
5810 boundtype[besti] = bestlbtypes[besti];
5811 varsign[besti] = +1;
5812 }
5813 *localbdsused = *localbdsused || (boundtype[besti] == -2);
5814 }
5815 }
5816 }
5817
5818 TERMINATE:
5819
5820 /*free temporary memory */
5821 SCIPfreeBufferArray(scip, &selectedbounds);
5822 SCIPfreeBufferArray(scip, &bestubtypes);
5823 SCIPfreeBufferArray(scip, &bestlbtypes);
5824 SCIPfreeBufferArray(scip, &bestubs);
5825 SCIPfreeBufferArray(scip, &bestlbs);
5826
5827 return SCIP_OKAY;
5828}
5829
5830/** Calculate fractionalities \f$ f_0 := b - down(b), f_j := a^\prime_j - down(a^\prime_j) \f$, and derive MIR cut \f$ \tilde{a} \cdot x' \leq down(b) \f$
5831 * \f[
5832 * \begin{array}{rll}
5833 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
5834 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
5835 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
5836 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
5837 * \end{array}
5838 * \f]
5839 *
5840 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
5841 *
5842 * (lb or ub):
5843 * \f[
5844 * \begin{array}{lllll}
5845 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation}, \\
5846 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation},
5847 * \end{array}
5848 * \f]
5849 * and move the constant terms
5850 * \f[
5851 * \begin{array}{cl}
5852 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
5853 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
5854 * \end{array}
5855 * \f]
5856 * to the rhs.
5857 *
5858 * (vlb or vub):
5859 * \f[
5860 * \begin{array}{lllll}
5861 * x^\prime_j := x_j - (bl_j \cdot zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
5862 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
5863 * \end{array}
5864 * \f]
5865 * move the constant terms
5866 * \f[
5867 * \begin{array}{cl}
5868 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
5869 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
5870 * \end{array}
5871 * \f]
5872 * to the rhs, and update the VB variable coefficients:
5873 * \f[
5874 * \begin{array}{ll}
5875 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
5876 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
5877 * \end{array}
5878 * \f]
5879 *
5880 * @note this method is safe for usage in exact solving mode
5881 */
5882static
5884 SCIP* scip, /**< SCIP data structure */
5885 SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
5886 SCIP_Real*RESTRICT cutrhs, /**< pointer to right hand side of cut */
5887 int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
5888 int*RESTRICT nnz, /**< number of non-zeros in cut */
5889 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
5890 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
5891 SCIP_INTERVAL f0 /**< fractional value of rhs */
5892 )
5893{
5894 SCIP_INTERVAL onedivoneminusf0;
5895 int i;
5896 int firstcontvar;
5897 SCIP_VAR** vars;
5898 int ndelcontvars;
5899 SCIP_ROUNDMODE previousroundmode;
5900 SCIP_MIRINFO* mirinfo = NULL;
5901 SCIP_INTERVAL tmpinterval;
5902
5903 assert(cutrhs != NULL);
5904 assert(cutcoefs != NULL);
5905 assert(cutinds != NULL);
5906 assert(nnz != NULL);
5907 assert(boundtype != NULL);
5908 assert(varsign != NULL);
5909 assert(0.0 < SCIPintervalGetInf(f0) && SCIPintervalGetSup(f0) < 1.0);
5911
5912 /* round up at first, since we are dividing and divisor should be as large as possible,
5913 * then switch to down since we are working on lhs */
5914 /* we need to careate the split-data for certification here, since part of the f_j > f_0 variables goes into the continuous part of the split */
5915 if( SCIPisCertified(scip) )
5917
5918 previousroundmode = SCIPintervalGetRoundingMode();
5919 tmpinterval = f0;
5921 SCIPintervalAddScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, 1.0);
5922 SCIPintervalSet(&onedivoneminusf0, 1.0);
5923 SCIPintervalDiv(SCIPinfinity(scip), &onedivoneminusf0, onedivoneminusf0, tmpinterval);
5925
5926 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
5927 * without destroying the ordering of the aggrrow's non-zeros.
5928 * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
5929 */
5930
5931 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5933#ifndef NDEBUG
5934 /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
5935 i = 0;
5936 while( i < *nnz && cutinds[i] >= firstcontvar )
5937 ++i;
5938
5939 while( i < *nnz )
5940 {
5941 assert(cutinds[i] < firstcontvar);
5942 ++i;
5943 }
5944#endif
5945
5946 /* round down everything on lhs (excepts for the denominator part above) */
5948
5949 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
5950 {
5951 SCIP_VAR* var;
5952 SCIP_INTERVAL cutaj;
5953
5954 int v;
5955
5956 v = cutinds[i];
5957 assert(0 <= v && v < SCIPgetNVars(scip));
5958
5959 var = vars[v];
5960 assert(var != NULL);
5962 assert(varsign[i] == +1 || varsign[i] == -1);
5963
5964 /* work on lhs -> round down */
5966
5967 /* calculate the coefficient in the retransformed cut */
5968 {
5969 SCIP_Real aj;
5970 SCIP_Real downaj;
5971 SCIP_Real fj;
5972
5973 aj = cutcoefs[v] * varsign[i];
5974
5975 downaj = floor(aj);
5976 fj = aj - downaj;
5977 assert(fj >= -SCIPepsilon(scip) && fj <= 1.0);
5978
5979 if( SCIPisLE(scip, fj, SCIPintervalGetInf(f0)) )
5980 {
5981 SCIPintervalSet(&cutaj, downaj);
5982
5983 if( SCIPisCertified(scip) && mirinfo != NULL )
5984 {
5985 SCIP_RATIONAL* boundval;
5986
5987 mirinfo->splitcoefficients[v] = SCIPintervalGetInf(cutaj); /*lint !e644*/
5988 assert(!SCIPisInfinity(scip, fabs(cutaj.inf)));
5989 if( mirinfo->upperused[v] )
5990 {
5991 mirinfo->splitcoefficients[v] *= -1;
5993 }
5994 else
5995 {
5997 }
5998 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
5999 }
6000 }
6001 else
6002 {
6003 SCIPintervalSet(&tmpinterval, aj);
6004 SCIPintervalSubScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, downaj);
6005 SCIPintervalSub(SCIPinfinity(scip), &tmpinterval, tmpinterval, f0);
6006 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, onedivoneminusf0);
6007 SCIPintervalAddScalar(SCIPinfinity(scip), &cutaj, tmpinterval, downaj);
6008
6009 if( SCIPisCertified(scip) && mirinfo != NULL )
6010 {
6011 SCIP_RATIONAL* boundval;
6012 mirinfo->splitcoefficients[v] = downaj;
6013 mirinfo->splitcoefficients[v] += 1.0;
6014 if( mirinfo->upperused[v] )
6015 {
6016 mirinfo->splitcoefficients[v] *= -1;
6018 }
6019 else
6020 {
6022 }
6023 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
6024 }
6025 }
6026
6027 SCIPintervalMulScalar(SCIPinfinity(scip), &cutaj, cutaj, (double) varsign[i]);
6028 }
6029
6030 /* integral var uses standard bound */
6031 assert(boundtype[i] < 0);
6032
6033 if( cutaj.inf != 0.0 || cutaj.sup != 0 )
6034 {
6035 /* we have to use the inf of the cutaj-interval both times! */
6037
6038 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6039 if( varsign[i] == +1 )
6040 {
6041 /* lower bound was used */
6042 if( boundtype[i] == -1 )
6043 {
6047 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6048 *cutrhs += SCIPintervalGetSup(tmpinterval);
6049 }
6050 else
6051 {
6054 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6055 *cutrhs += SCIPintervalGetSup(tmpinterval);
6056 }
6057 }
6058 else
6059 {
6060 /* upper bound was used */
6061 if( boundtype[i] == -1 )
6062 {
6066 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6067 *cutrhs += SCIPintervalGetSup(tmpinterval);
6068 }
6069 else
6070 {
6073 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6074 *cutrhs += SCIPintervalGetSup(tmpinterval);
6075 }
6076 }
6077 }
6078
6079 /* remove zero cut coefficients from cut, only remove exactly 0 in exact solving mode
6080 * we can only do this here, since the sup might be positive and impact the rhs of the cut */
6081 if( cutaj.inf == 0.0 )
6082 {
6083 cutcoefs[v] = 0.0;
6084 --*nnz;
6085 cutinds[i] = cutinds[*nnz];
6086 continue;
6087 }
6088
6089 cutcoefs[v] = SCIPintervalGetInf(cutaj);
6090 }
6091
6092 /* adapt lhs -> round down */
6094
6095 /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
6096 ndelcontvars = 0;
6097 while( i >= ndelcontvars )
6098 {
6099 SCIP_VAR* var;
6100 SCIP_INTERVAL cutaj;
6101 SCIP_Real aj;
6102 int v;
6103
6104 v = cutinds[i];
6105 assert(0 <= v && v < SCIPgetNVars(scip));
6106
6107 var = vars[v];
6108 assert(var != NULL);
6110 assert(varsign[i] == +1 || varsign[i] == -1);
6111 assert( v >= firstcontvar );
6112
6113 /* adapt lhs -> round down */
6115
6116 /* calculate the coefficient in the retransformed cut */
6117 aj = cutcoefs[v];
6118
6119 if( aj * varsign[i] >= 0.0 )
6120 SCIPintervalSet(&cutaj, 0.0);
6121 else
6122 {
6123 SCIPintervalMulScalar(SCIPinfinity(scip), &cutaj, onedivoneminusf0, aj); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
6124 }
6125
6126 /* remove zero cut coefficients from cut; move a continuous var from the beginning
6127 * to the current position, so that all integral variables stay behind the continuous
6128 * variables
6129 */
6130 if( EPSZ(SCIPintervalGetInf(cutaj), QUAD_EPSILON) && (SCIPintervalGetInf(cutaj) >= 0.0) )
6131 {
6132 SCIPintervalSet(&cutaj, 0.0);
6133 cutcoefs[v] = 0.0;
6134 cutinds[i] = cutinds[ndelcontvars];
6135 varsign[i] = varsign[ndelcontvars];
6136 boundtype[i] = boundtype[ndelcontvars];
6137 ++ndelcontvars;
6138 continue;
6139 }
6140
6141 cutcoefs[v] = SCIPintervalGetInf(cutaj);
6142
6144
6145 /* check for variable bound use */
6146 if( boundtype[i] < 0 )
6147 {
6148 /* standard bound */
6149
6150 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6151 if( varsign[i] == +1 )
6152 {
6153 /* lower bound was used */
6154 if( boundtype[i] == -1 )
6155 {
6158 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6159 *cutrhs += SCIPintervalGetSup(tmpinterval);
6160 }
6161 else
6162 {
6165 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6166 *cutrhs += SCIPintervalGetSup(tmpinterval);
6167 }
6168 }
6169 else
6170 {
6171 /* upper bound was used */
6172 if( boundtype[i] == -1 )
6173 {
6176 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6177 *cutrhs += SCIPintervalGetSup(tmpinterval);
6178 }
6179 else
6180 {
6183 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6184 *cutrhs += SCIPintervalGetSup(tmpinterval);
6185 }
6186 }
6187 }
6188 else
6189 {
6190 SCIPerrorMessage("varbounds not yet implemented in exact SCIP \n");
6191 return SCIP_ERROR;
6192 }
6193
6194 /* advance to next variable */
6195 --i;
6196 }
6197
6198 /* fill the empty position due to deleted continuous variables */
6199 if( ndelcontvars > 0 )
6200 {
6201 assert(ndelcontvars <= *nnz);
6202 *nnz -= ndelcontvars;
6203 if( *nnz < ndelcontvars )
6204 {
6205 BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
6206 }
6207 else
6208 {
6209 BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
6210 }
6211 }
6212
6213 /* reset rounding mode, also set the rhs->data in the mirinfo */
6214 SCIPintervalSetRoundingMode(previousroundmode);
6215
6216 return SCIP_OKAY;
6217}
6218
6219#ifdef SCIP_DISABLED_CODE
6220/** Calculate fractionalities \f$ f_0 := b - down(b), f_j := a^\prime_j - down(a^\prime_j) \f$, and derive MIR cut \f$ \tilde{a} \cdot x' \leq down(b) \f$
6221 * \f[
6222 * \begin{array}{rll}
6223 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
6224 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
6225 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
6226 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
6227 * \end{array}
6228 * \f]
6229 *
6230 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
6231 *
6232 * (lb or ub):
6233 * \f[
6234 * \begin{array}{lllll}
6235 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation} \\
6236 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation}
6237 * \end{array}
6238 * \f]
6239 * and move the constant terms
6240 * \f[
6241 * \begin{array}{cl}
6242 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
6243 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
6244 * \end{array}
6245 * \f]
6246 * to the rhs.
6247 *
6248 * (vlb or vub):
6249 * \f[
6250 * \begin{array}{lllll}
6251 * x^\prime_j := x_j - (bl_j \cdot zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
6252 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
6253 * \end{array}
6254 * \f]
6255 * move the constant terms
6256 * \f[
6257 * \begin{array}{cl}
6258 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
6259 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
6260 * \end{array}
6261 * \f]
6262 * to the rhs, and update the VB variable coefficients:
6263 * \f[
6264 * \begin{array}{ll}
6265 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
6266 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
6267 * \end{array}
6268 * \f]
6269 *
6270 * @note this method is safe for usage in exact solving mode
6271 */
6272static
6273SCIP_RETCODE cutsRoundMIRRational(
6274 SCIP* scip, /**< SCIP data structure */
6275 SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
6276 QUAD(SCIP_Real*RESTRICT cutrhs), /**< pointer to right hand side of cut */
6277 int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
6278 int*RESTRICT nnz, /**< number of non-zeros in cut */
6279 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
6280 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
6281 SCIP_RATIONAL* f0 /**< fractional value of rhs */
6282 )
6283{
6284 SCIP_RATIONAL* tmp;
6285 SCIP_RATIONAL* onedivoneminusf0;
6286 int i;
6287 int firstcontvar;
6288 SCIP_VAR** vars;
6289 int ndelcontvars;
6290 SCIP_ROUNDMODE previousroundmode;
6291 SCIP_MIRINFO* mirinfo;
6292
6293 assert(QUAD_HI(cutrhs) != NULL);
6294 assert(cutcoefs != NULL);
6295 assert(cutinds != NULL);
6296 assert(nnz != NULL);
6297 assert(boundtype != NULL);
6298 assert(varsign != NULL);
6301
6302 SCIP_CALL( SCIPrationalCreateBuffer(SCIPbuffer(scip), &onedivoneminusf0) );
6304
6305 /* round up at first, since we are dividing and divisor should be as large as possible,
6306 * then switch to down since we are working on lhs */
6307 /* we need to careate the split-data for certification here, since part of the f_j > f_0 variables goes into the continuous part of the split */
6308 if( SCIPisCertified(scip) )
6310
6311 previousroundmode = SCIPintervalGetRoundingMode();
6312 SCIPrationalSetReal(tmp, 1.0);
6313 SCIPrationalDiff(tmp, tmp, f0);
6314 SCIPrationalSetReal(onedivoneminusf0, 1.0);
6315 SCIPrationalDiv(onedivoneminusf0, onedivoneminusf0, tmp);
6316
6317 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
6318 * without destroying the ordering of the aggrrow's non-zeros.
6319 * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
6320 */
6321
6322 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
6324#ifndef NDEBUG
6325 /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
6326 i = 0;
6327 while( i < *nnz && cutinds[i] >= firstcontvar )
6328 ++i;
6329
6330 while( i < *nnz )
6331 {
6332 assert(cutinds[i] < firstcontvar);
6333 ++i;
6334 }
6335#endif
6336
6337 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
6338 {
6339 SCIP_VAR* var;
6340 SCIP_RATIONAL* cutaj;
6341 SCIP_Real QUAD(cutajquad);
6342 int v;
6343
6344 v = cutinds[i];
6345 assert(0 <= v && v < SCIPgetNVars(scip));
6346
6348
6349 var = vars[v];
6350 assert(var != NULL);
6352 assert(varsign[i] == +1 || varsign[i] == -1);
6353
6354 /* calculate the coefficient in the retransformed cut */
6355 {
6356 SCIP_Real QUAD(aj);
6357 SCIP_Real downaj;
6358 SCIP_RATIONAL* fj;
6359
6361
6362 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
6363 QUAD_SCALE(aj, varsign[i]);
6364 SCIPrationalSetReal(tmp, aj);
6365
6366 downaj = floor(QUAD_TO_DBL(aj));
6367 SCIPrationalDiffReal(fj, tmp, downaj);
6368
6369 if( SCIPrationalIsLE(fj, f0) )
6370 {
6371 SCIPrationalSetReal(cutaj, downaj);
6372
6373 if( SCIPisCertified(scip) )
6374 {
6375 SCIP_RATIONAL* boundval;
6376
6377 mirinfo->splitcoefficients[v] = downaj;
6378 if( mirinfo->upperused[v] )
6379 {
6380 mirinfo->splitcoefficients[v] *= -1;
6382 }
6383 else
6384 {
6386 }
6387 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
6388 }
6389 }
6390 else
6391 {
6393 SCIPrationalDiffReal(tmp, tmp, downaj);
6394 SCIPrationalDiff(tmp, tmp, f0);
6395 SCIPrationalMult(tmp, tmp, onedivoneminusf0);
6396 SCIPrationalAddReal(cutaj, tmp, downaj);
6397
6398 if( SCIPisCertified(scip) )
6399 {
6400 SCIP_RATIONAL* boundval;
6401
6402 mirinfo->splitcoefficients[v] = QUAD_TO_DBL(downaj);
6403 mirinfo->splitcoefficients[v] += 1.0;
6404 if( mirinfo->upperused[v] )
6405 {
6406 mirinfo->splitcoefficients[v] *= -1;
6408 }
6409 else
6410 {
6412 }
6413 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
6414 }
6415 }
6416
6417 SCIPrationalMultReal(cutaj, cutaj, varsign[i]);
6418
6420 }
6421
6422 /* remove zero cut coefficients from cut, only remove positive coefficients in exact solving mode */
6423 if( SCIPrationalIsZero(cutaj) )
6424 {
6425 QUAD_ASSIGN(cutajquad, 0.0);
6426 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
6427 --*nnz;
6428 cutinds[i] = cutinds[*nnz];
6430 continue;
6431 }
6432
6434
6435 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
6436
6437 /* integral var uses standard bound */
6438 assert(boundtype[i] < 0);
6439
6441
6442 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6443 if( varsign[i] == +1 )
6444 {
6445 /* lower bound was used */
6446 if( boundtype[i] == -1 )
6447 {
6451 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetLbGlobal(var) */
6452 }
6453 else
6454 {
6457 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetLbLocal(var) */
6458 }
6459 }
6460 else
6461 {
6462 /* upper bound was used */
6463 if( boundtype[i] == -1 )
6464 {
6468 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetUbGlobal(var) */
6469 }
6470 else
6471 {
6474 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetUbLocal(var) */
6475 }
6476 }
6478 }
6479
6480 /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
6481 ndelcontvars = 0;
6482 while( i >= ndelcontvars )
6483 {
6484 SCIP_VAR* var;
6485 SCIP_RATIONAL* cutaj;
6486 SCIP_RATIONAL* tmprational;
6487 SCIP_Real QUAD(cutajquad);
6488 SCIP_Real QUAD(aj);
6489 int v;
6490
6491 /* adapt lhs -> round down */
6493
6496
6497 v = cutinds[i];
6498 assert(0 <= v && v < SCIPgetNVars(scip));
6499
6500 var = vars[v];
6501 assert(var != NULL);
6503 assert(varsign[i] == +1 || varsign[i] == -1);
6504 assert( v >= firstcontvar );
6505
6506 /* calculate the coefficient in the retransformed cut */
6507 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
6508
6509 if( QUAD_TO_DBL(aj) * varsign[i] >= 0.0 )
6510 SCIPrationalSetReal(cutaj, 0.0);
6511 else
6512 {
6513 SCIPrationalSetRational(cutaj, onedivoneminusf0);
6514 SCIPrationalMultReal(cutaj, cutaj, QUAD_TO_DBL(aj)); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
6515 }
6516
6517 /* remove zero cut coefficients from cut; move a continuous var from the beginning
6518 * to the current position, so that all integral variables stay behind the continuous
6519 * variables
6520 */
6521 if( EPSZ(SCIPrationalGetReal(cutaj), QUAD_EPSILON) && SCIPrationalIsGEReal(cutaj, 0.0) )
6522 {
6523 assert(SCIPrationalIsZero(cutaj));
6524 SCIPrationalSetReal(cutaj, 0.0);
6525 QUAD_ASSIGN_Q(cutajquad, 0.0);
6526 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
6527 cutinds[i] = cutinds[ndelcontvars];
6528 varsign[i] = varsign[ndelcontvars];
6529 boundtype[i] = boundtype[ndelcontvars];
6530 ++ndelcontvars;
6531
6532 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
6534
6535 continue;
6536 }
6537
6539 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
6540
6542
6543 /* check for variable bound use */
6544 if( boundtype[i] < 0 )
6545 {
6546 /* standard bound */
6547
6548 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6549 if( varsign[i] == +1 )
6550 {
6551 /* lower bound was used */
6552 if( boundtype[i] == -1 )
6553 {
6556 SCIPrationalMult(tmprational, cutaj, SCIPvarGetLbGlobalExact(var));
6557 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
6558 }
6559 else
6560 {
6562 SCIPrationalMult(tmprational, cutaj, SCIPvarGetLbLocalExact(var));
6563 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
6564 }
6565 }
6566 else
6567 {
6568 /* upper bound was used */
6569 if( boundtype[i] == -1 )
6570 {
6573 SCIPrationalMult(tmprational, cutaj, SCIPvarGetUbGlobalExact(var));
6574 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
6575 }
6576 else
6577 {
6579 SCIPrationalMult(tmprational, cutaj, SCIPvarGetUbLocalExact(var));
6580 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
6581 }
6582 }
6583
6584 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
6586 }
6587 else
6588 {
6589#ifdef SCIP_DISABLED_CODE
6590 SCIP_VAR** vbz;
6591 SCIP_Real* vbb;
6592 SCIP_Real* vbd;
6593 SCIP_Real QUAD(zcoef);
6594 int vbidx;
6595 int zidx;
6596
6598
6599 /* variable bound */
6600 vbidx = boundtype[i];
6601
6602 /* change mirrhs and cutaj of integer variable z_j of variable bound */
6603 if( varsign[i] == +1 )
6604 {
6605 /* variable lower bound was used */
6606 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
6607 vbz = SCIPvarGetVlbVars(var);
6608 vbb = SCIPvarGetVlbCoefs(var);
6610 }
6611 else
6612 {
6613 /* variable upper bound was used */
6614 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
6615 vbz = SCIPvarGetVubVars(var);
6616 vbb = SCIPvarGetVubCoefs(var);
6618 }
6619 assert(SCIPvarIsActive(vbz[vbidx]));
6620 zidx = SCIPvarGetProbindex(vbz[vbidx]);
6621 assert(0 <= zidx && zidx < firstcontvar);
6622
6623 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
6624 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
6625
6626 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
6627 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
6628
6629 /* update sparsity pattern */
6630 if( QUAD_HI(zcoef) == 0.0 )
6631 cutinds[(*nnz)++] = zidx;
6632
6633 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
6634 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
6635 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
6636 assert(QUAD_HI(zcoef) != 0.0);
6637#endif
6638 }
6639
6640 /* advance to next variable */
6641 --i;
6642 }
6643
6644 /* fill the empty position due to deleted continuous variables */
6645 if( ndelcontvars > 0 )
6646 {
6647 assert(ndelcontvars <= *nnz);
6648 *nnz -= ndelcontvars;
6649 if( *nnz < ndelcontvars )
6650 {
6651 BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
6652 }
6653 else
6654 {
6655 BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
6656 }
6657 }
6658
6659 /* reset rounding mode, also set the rhs->data in the mirinfo */
6660 SCIPintervalSetRoundingMode(previousroundmode);
6661
6663 SCIPrationalFreeBuffer(SCIPbuffer(scip), &onedivoneminusf0);
6664
6665 return SCIP_OKAY;
6666}
6667#endif
6668
6669
6670/** Calculate fractionalities \f$ f_0 := b - down(b), f_j := a^\prime_j - down(a^\prime_j) \f$, and derive MIR cut \f$ \tilde{a} \cdot x' \leq down(b) \f$
6671 * \f[
6672 * \begin{array}{rll}
6673 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
6674 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
6675 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
6676 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
6677 * \end{array}
6678 * \f]
6679 *
6680 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
6681 *
6682 * (lb or ub):
6683 * \f[
6684 * \begin{array}{lllll}
6685 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation} \\
6686 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation}
6687 * \end{array}
6688 * \f]
6689 * and move the constant terms
6690 * \f[
6691 * \begin{array}{cl}
6692 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
6693 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
6694 * \end{array}
6695 * \f]
6696 * to the rhs.
6697 *
6698 * (vlb or vub):
6699 * \f[
6700 * \begin{array}{lllll}
6701 * x^\prime_j := x_j - (bl_j \cdot zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
6702 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
6703 * \end{array}
6704 * \f]
6705 * move the constant terms
6706 * \f[
6707 * \begin{array}{cl}
6708 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
6709 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
6710 * \end{array}
6711 * \f]
6712 * to the rhs, and update the VB variable coefficients:
6713 * \f[
6714 * \begin{array}{ll}
6715 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
6716 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
6717 * \end{array}
6718 * \f]
6719 */
6720static
6722 SCIP* scip, /**< SCIP data structure */
6723 MIR_DATA* data, /**< the MIR data structure for this cut */
6724 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
6725 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
6726 QUAD(SCIP_Real f0) /**< fractional value of rhs */
6727 )
6728{
6729 SCIP_Real QUAD(tmp);
6730 SCIP_Real QUAD(onedivoneminusf0);
6731 int s;
6732 int cutindex;
6733 int i;
6734
6735 assert(data != NULL);
6736 assert(boundtype != NULL);
6737 assert(varsign != NULL);
6738 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
6739
6740 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
6741 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
6742
6743 /* Loop backwards through the sections, so that the reversing of varbound substitutions does not prematurely effect
6744 * the coefficients of variables in other sections, because the section index of a variable bound must always be
6745 * higher than that of the bounded variable. */
6746 cutindex = data->ncutinds - 1;
6747 for( s = NSECTIONS - 1; s >= 0; --s )
6748 {
6749 int* indices = data->secindices[s];
6750 int nnz = data->secnnz[s];
6751
6752 SCIP_Bool enfintegral = data->isenfint[s];
6753 SCIP_Bool implintegral = data->isimplint[s];
6754
6755 /* iterate backwards over indices in section, so we can easily shrink the section if we find zeros */
6756 for( i = nnz - 1; i >= 0 ; --i )
6757 {
6758 int v;
6759 int sign;
6760 int type;
6761 SCIP_Real QUAD(cutaj);
6762 SCIP_Real QUAD(aj);
6763 SCIP_VAR* var;
6764
6765 v = indices[i];
6766 assert(0 <= v && v < data->nvars);
6767 assert(data->cutinds[cutindex] == v);
6768
6769 sign = varsign[cutindex];
6770 assert(sign == +1 || sign == -1);
6771 type = boundtype[cutindex];
6772
6773 --cutindex;
6774
6775 var = data->vars[v];
6776 assert(var != NULL);
6778
6779 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
6780
6781 if( enfintegral || implintegral )
6782 {
6783 /* variable is integral */
6784 SCIP_Real QUAD(downaj);
6785 SCIP_Real QUAD(fj);
6786
6787 QUAD_SCALE(aj, sign);
6788
6789 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
6790 SCIPquadprecSumQQ(fj, aj, -downaj);
6791 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
6792
6793 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
6794 {
6795 QUAD_ASSIGN_Q(cutaj, downaj); /* a^_j */
6796 }
6797 else
6798 {
6799 SCIPquadprecSumQQ(tmp, fj, -f0);
6800 SCIPquadprecProdQQ(tmp, tmp, onedivoneminusf0);
6801 SCIPquadprecSumQQ(cutaj, tmp, downaj);
6802 }
6803 QUAD_SCALE(cutaj, sign);
6804 }
6805 else
6806 {
6807 /* variable is continuous */
6809
6810 if( QUAD_TO_DBL(aj) * sign >= 0.0 )
6811 QUAD_ASSIGN(cutaj, 0.0);
6812 else
6813 SCIPquadprecProdQQ(cutaj, onedivoneminusf0, aj); /* cutaj = aj * onedivoneminusf0 */
6814 }
6815
6816 /* remove coefficient from cut if it becomes zero */
6817 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
6818 {
6819 QUAD_ASSIGN(cutaj, 0.0);
6820 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
6821 --data->totalnnz;
6822 --data->secnnz[s];
6823 indices[i] = indices[data->secnnz[s]];
6824 continue;
6825 }
6826
6827 /* store the updated coefficient */
6828 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
6829
6830 /* undo bound transformations */
6831 if( type < 0 )
6832 {
6833 /* standard bound */
6834 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6835 if( sign == +1 )
6836 {
6837 /* lower bound was used */
6838 if( type == -1 )
6839 {
6842 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6843 }
6844 else
6845 {
6848 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6849 }
6850 }
6851 else
6852 {
6853 /* upper bound was used */
6854 if( type == -1 )
6855 {
6858 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6859 }
6860 else
6861 {
6864 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6865 }
6866 }
6867 }
6868 else
6869 {
6870 /* variable bound */
6871 SCIP_VAR** vbz;
6872 SCIP_Real* vbb;
6873 SCIP_Real* vbd;
6874 SCIP_Real QUAD(zcoef);
6875 int vbidx;
6876 int zidx;
6877
6878 /* variable bound */
6879 vbidx = type;
6880
6881 /* change mirrhs and cutaj of integer variable z_j of variable bound */
6882 if( sign == +1 )
6883 {
6884 /* variable lower bound was used */
6885 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
6886 vbz = SCIPvarGetVlbVars(var);
6887 vbb = SCIPvarGetVlbCoefs(var);
6889 }
6890 else
6891 {
6892 /* variable upper bound was used */
6893 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
6894 vbz = SCIPvarGetVubVars(var);
6895 vbb = SCIPvarGetVubCoefs(var);
6897 }
6898 assert(SCIPvarIsActive(vbz[vbidx]));
6899 zidx = SCIPvarGetProbindex(vbz[vbidx]);
6900 assert(varSection(data, zidx) > s);
6901
6902 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
6903 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6904
6905 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
6906 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
6907
6908 /* update sparsity pattern */
6909 if( QUAD_HI(zcoef) == 0.0 )
6910 {
6911 int zsection = varSection(data, zidx);
6912 data->secindices[zsection][data->secnnz[zsection]] = zidx;
6913 ++data->secnnz[zsection];
6914 ++data->totalnnz;
6915 }
6916
6917 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
6918 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
6919 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
6920 assert(QUAD_HI(zcoef) != 0.0);
6921 }
6922 }
6923 }
6924
6925 /* Finally, store the relevant data in cutinds which is the array used by the other functions */
6926 data->ncutinds = 0;
6927 for( s = 0; s < NSECTIONS; ++s )
6928 {
6929 int* indices = data->secindices[s];
6930 int nnz = data->secnnz[s];
6931 for( i = 0; i < nnz; ++i )
6932 {
6933 data->cutinds[data->ncutinds] = indices[i];
6934 ++data->ncutinds;
6935 }
6936 }
6937 return SCIP_OKAY;
6938}
6939
6940/** substitute aggregated slack variables:
6941 *
6942 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
6943 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r]. \f$
6944 *
6945 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
6946 * \f[
6947 * \begin{array}{rll}
6948 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r \leq f_0 \\
6949 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f_0)/(1 - f_0),& \mbox{if}\qquad f_r > f_0 \\
6950 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r \geq 0 \\
6951 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f_0), & \mbox{if}\qquad a^\prime_r < 0
6952 * \end{array}
6953 * \f]
6954 *
6955 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
6956 *
6957 * @note this method is safe for usage in exact solving mode
6958 *
6959 * @todo certify and use integrality of row in exact solving mode
6960 *
6961 * @todo make behavior identical to the unsafe MIR cut computation
6962 */
6963static
6965 SCIP* scip, /**< SCIP data structure */
6966 SCIP_Real* weights, /**< row weights in row summation */
6967 int* slacksign, /**< stores the sign of the row's slack variable in summation */
6968 int* rowinds, /**< sparsity pattern of used rows */
6969 int nrowinds, /**< number of used rows */
6970 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
6971 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
6972 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
6973 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
6974 int* nnz, /**< number of non-zeros in cut */
6975 SCIP_INTERVAL f0 /**< fractional value of rhs */
6976 )
6977{ /*lint --e{715}*/
6978 SCIP_ROW** rows;
6979 SCIP_ROW* userow;
6980 SCIP_ROWEXACT* rowexact;
6981 SCIP_INTERVAL onedivoneminusf0, tmpinterval;
6982 SCIP_ROUNDMODE previousroundmode;
6983 SCIP_AGGREGATIONINFO* aggrinfo = NULL;
6984 SCIP_MIRINFO* mirinfo = NULL;
6985 SCIP_Real mult;
6986 SCIP_Real splitcoef;
6987 SCIP_Real slackweight;
6988 SCIP_Bool slackroundeddown;
6989 int i;
6990 int currentnegslackrow;
6991
6992 assert(scip != NULL);
6993 assert(weights != NULL || nrowinds == 0);
6994 assert(slacksign != NULL || nrowinds == 0);
6995 assert(rowinds != NULL || nrowinds == 0);
6996 assert(scale > 0.0);
6997 assert(cutcoefs != NULL);
6998 assert(cutrhs != NULL);
6999 assert(cutinds != NULL);
7000 assert(nnz != NULL);
7001 assert(0.0 < SCIPintervalGetInf(f0) && SCIPintervalGetSup(f0) < 1.0);
7002
7004
7005 /* compute 1/(1-f0) in interval arithmetic */
7006 previousroundmode = SCIPintervalGetRoundingMode();
7008 SCIPintervalAddScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, 1.0);
7009 SCIPintervalSet(&onedivoneminusf0, 1.0);
7010 SCIPintervalDiv(SCIPinfinity(scip), &onedivoneminusf0, onedivoneminusf0, tmpinterval);
7011
7012 if( SCIPisCertified(scip) )
7013 {
7016 }
7017
7018 rows = SCIPgetLPRows(scip);
7019 currentnegslackrow = 0;
7020 for( i = 0; i < nrowinds; i++ )
7021 {
7022 SCIP_ROW* row;
7023 SCIP_INTERVAL ar;
7024 SCIP_INTERVAL cutar;
7025 int r;
7026 SCIP_Bool integralslack = FALSE;
7027
7028 r = rowinds[i]; /*lint !e613*/
7029 assert(0 <= r && r < SCIPgetNLPRows(scip));
7030 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
7031 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
7032
7033 row = rows[r];
7034 assert(row != NULL);
7035 assert(row->len == 0 || row->cols != NULL);
7036 assert(row->len == 0 || row->cols_index != NULL);
7037 assert(row->len == 0 || row->vals != NULL);
7038
7039 if( slacksign[i] == 1 )
7041 else
7043
7044 /* get the slack's coefficient a'_r = weights[i] * scale in the aggregated row */
7045 SCIPintervalSet(&ar, weights[i]);
7046 SCIPintervalMulScalar(SCIPinfinity(scip), &ar, ar, scale);
7047 SCIPintervalMulScalar(SCIPinfinity(scip), &ar, ar, (double) slacksign[i]);
7048
7049 /* calculate slack variable's coefficient a^_r in the cut */
7050 if( row->integral &&
7051 ((slacksign[i] == +1 && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant))
7052 || (slacksign[i] == -1 && SCIPrealIsExactlyIntegral(row->lhs) && SCIPrealIsExactlyIntegral(row->constant))) ) /*lint !e613*/
7053 {
7054 /* slack variable is always integral:
7055 * a^_r = a~_r = down(a'_r) , if f_r <= f0
7056 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
7057 */
7058 SCIP_Real downar;
7059 SCIP_INTERVAL fr;
7060
7061 SCIPdebugMessage("resubstituting integer slack for row %s\n", row->name);
7062 downar = floor(ar.inf);
7063 SCIPintervalSubScalar(SCIPinfinity(scip), &fr, ar, downar);
7064
7065 integralslack = TRUE;
7066
7067 if( SCIPisLE(scip, fr.inf, f0.inf) )
7068 {
7069 SCIPintervalSet(&cutar, downar);
7070 splitcoef = downar;
7071 slackweight = weights[i];
7072 slackroundeddown = TRUE;
7073 SCIPintervalMul(SCIPinfinity(scip), &fr, fr, onedivoneminusf0);
7074 SCIPdebugMessage("fractionality %g, f0 %g -> round down to %g\n", fr.inf, f0.inf, splitcoef);
7075 }
7076 else
7077 {
7078 SCIPintervalSetBounds(&cutar, ar.inf, ar.sup);
7079 SCIPintervalSubScalar(SCIPinfinity(scip), &cutar, cutar, downar);
7080 SCIPintervalSub(SCIPinfinity(scip), &cutar, cutar, f0);
7081 SCIPintervalMul(SCIPinfinity(scip), &cutar, cutar, onedivoneminusf0);
7082 SCIPintervalAddScalar(SCIPinfinity(scip), &cutar, cutar, downar);
7083 splitcoef = downar + 1;
7084 slackweight = weights[i];
7085 slackroundeddown = FALSE;
7086 SCIPdebugMessage("fractionality %g, f0 %g -> round up! splitcoef %g sub-coefficient %g", fr.inf, f0.inf, splitcoef, cutar.inf);
7087 }
7088 }
7089 else
7090 {
7091 /* slack variable is continuous:
7092 * a^_r = a~_r = 0 , if a'_r >= 0
7093 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
7094 */
7095 if( SCIPintervalGetInf(ar) >= 0.0 )
7096 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
7097 else
7098 {
7099 SCIPintervalMul(SCIPinfinity(scip), &cutar, onedivoneminusf0, ar); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
7100 SCIPdebugMessage("resubstituting negative continuous slack for row %s with coef %g\n", row->name, cutar.inf);
7101 }
7102 }
7103
7104 rowexact = SCIProwGetRowExact(row);
7105 assert(SCIProwExactHasFpRelax(rowexact));
7106 if( SCIProwExactGetRowRhs(rowexact) != NULL && slacksign[i] == 1.0 )
7107 userow = SCIProwExactGetRowRhs(rowexact);
7108 else
7109 userow = row;
7110
7111 SCIPintervalMulScalar(SCIPinfinity(scip), &cutar, cutar, (double) -slacksign[i]);
7112
7113 if( slacksign[i] == -1 )
7114 mult = cutar.inf;
7115 else
7116 mult = cutar.sup;
7117
7118 if( SCIPisCertified(scip) && integralslack) /*lint --e{644}*/
7119 {
7120 assert(mirinfo != NULL);
7121 /* save the value for the split disjunction for the integer slack and the continous part (for rounded up we
7122 * subtract 1-f); multiply by -slacksign (same as above) since slack = side - row
7123 */
7124 mirinfo->slackrows[mirinfo->nslacks] = userow;
7125 SCIP_CALL( SCIPcaptureRow(scip, userow) );
7126 mirinfo->slackcoefficients[mirinfo->nslacks] = splitcoef * (-slacksign[i]);
7127 mirinfo->slacksign[mirinfo->nslacks] = slacksign[i];
7129 mirinfo->slackweight[mirinfo->nslacks] = slackweight;
7130 mirinfo->slackscale[mirinfo->nslacks] = scale;
7131 mirinfo->slackusedcoef[mirinfo->nslacks] = mult;
7132
7133 /* save the value that goes into the certificate aggregation row (either downar or ar) */
7134 mirinfo->slackroundeddown[mirinfo->nslacks] = slackroundeddown;
7135 if( slackroundeddown )
7136 mirinfo->nrounddownslacks++;
7137 mirinfo->nslacks++;
7138 }
7139
7140 /* if the coefficient was reduced to zero, ignore the slack variable */
7141 if( EPSZ(SCIPintervalGetInf(cutar), QUAD_EPSILON) && (SCIPintervalGetInf(cutar) >= 0.0) )
7142 continue;
7143
7144 /* depending on the slack's sign, we have
7145 * - sign = 1: s = rhs - a^Tx >= 0
7146 * - sign = -1: s = lhs - a^Tx <= 0
7147 */
7148 {
7149 SCIP_Bool success = TRUE;
7150 SCIP_Real sidevalchg;
7151
7152 if( SCIPisCertified(scip) && !integralslack )
7153 {
7154 assert(aggrinfo != NULL);
7155 assert(aggrinfo->negslackweights[currentnegslackrow] == -weights[i]); /*lint !e777*/
7156 aggrinfo->substfactor[currentnegslackrow] = mult;
7157 currentnegslackrow++;
7158 }
7159
7160 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, cutinds, cutcoefs, nnz, userow, mult, &sidevalchg, &success) );
7161 assert(success);
7162
7163 /* move to rhs -> need to round up */
7165 *cutrhs += sidevalchg;
7166 }
7167
7168 /* move slack's constant to the right hand side */
7169 if( slacksign[i] == +1 ) /*lint !e613*/
7170 {
7171 SCIP_INTERVAL rowrhs;
7172
7174 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7175 assert(!SCIPisInfinity(scip, userow->rhs));
7176 SCIPintervalSet(&rowrhs, userow->rhs);
7177 SCIPintervalSubScalar(SCIPinfinity(scip), &rowrhs, rowrhs, userow->constant);
7178#ifdef SCIP_DISABLED_CODE
7179 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
7180 if( row->integral )
7181 {
7182 /* the right hand side was implicitly rounded down in row aggregation */
7183 QUAD_ASSIGN(rowrhs, floor(QUAD_TO_DBL(rowrhs)));
7184 }
7185#endif
7186 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, cutar, rowrhs);
7187 *cutrhs += SCIPintervalGetSup(tmpinterval);
7188 }
7189 else
7190 {
7191 SCIP_INTERVAL rowlhs;
7192
7194 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7195 assert(!SCIPisInfinity(scip, -userow->lhs));
7196 SCIPintervalSet(&rowlhs, userow->lhs);
7197 SCIPintervalSubScalar(SCIPinfinity(scip), &rowlhs, rowlhs, userow->constant);
7198#ifdef SCIP_DISABLED_CODE
7199 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
7200 if( row->integral )
7201 {
7202 /* the left hand side was implicitly rounded up in row aggregation */
7203 QUAD_ASSIGN(rowlhs, floor(QUAD_TO_DBL(rowlhs)));
7204 }
7205#endif
7206 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, cutar, rowlhs);
7207 *cutrhs += SCIPintervalGetSup(tmpinterval);
7208 }
7209 }
7210
7211 /* relax rhs to zero, if it's very close to 0 */
7212 if( *cutrhs < 0.0 && *cutrhs >= SCIPepsilon(scip) )
7213 *cutrhs = 0.0;
7214
7215 SCIPintervalSetRoundingMode(previousroundmode);
7216
7217 return SCIP_OKAY;
7218}
7219
7220#ifdef SCIP_DISABLED_CODE
7221/** substitute aggregated slack variables:
7222 *
7223 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
7224 * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
7225 *
7226 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
7227 * \f[
7228 * \begin{array}{rll}
7229 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
7230 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
7231 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
7232 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
7233 * \end{array}
7234 * \f]
7235 *
7236 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
7237 *
7238 * @note this method is safe for usage in exact solving mode
7239 */
7240static
7241SCIP_RETCODE cutsSubstituteMIRRational(
7242 SCIP* scip, /**< SCIP data structure */
7243 SCIP_Real* weights, /**< row weights in row summation */
7244 int* slacksign, /**< stores the sign of the row's slack variable in summation */
7245 int* rowinds, /**< sparsity pattern of used rows */
7246 int nrowinds, /**< number of used rows */
7247 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
7248 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7249 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
7250 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7251 int* nnz, /**< number of non-zeros in cut */
7252 SCIP_RATIONAL* f0 /**< fractional value of rhs */
7253 )
7254{ /*lint --e{715}*/
7255 SCIP_ROW** rows;
7256 SCIP_ROW* userow;
7257 SCIP_ROWEXACT* rowexact;
7258 SCIP_RATIONAL* onedivoneminusf0;
7259 SCIP_RATIONAL* tmprational;
7260 SCIP_ROUNDMODE previousroundmode;
7261 SCIP_AGGREGATIONINFO* aggrinfo;
7262 SCIP_Real mult;
7263 int i;
7264 int currentnegslackrow;
7265 SCIP_RATIONAL* ar;
7266 SCIP_RATIONAL* cutar;
7267 int r;
7268
7269 assert(scip != NULL);
7270 assert(weights != NULL || nrowinds == 0);
7271 assert(slacksign != NULL || nrowinds == 0);
7272 assert(rowinds != NULL || nrowinds == 0);
7273 assert(scale > 0.0);
7274 assert(cutcoefs != NULL);
7275 assert(QUAD_HI(cutrhs) != NULL);
7276 assert(cutinds != NULL);
7277 assert(nnz != NULL);
7279
7281 SCIP_CALL( SCIPrationalCreateBuffer(SCIPbuffer(scip), &onedivoneminusf0) );
7284
7285 /* compute 1/(1-f0) in interval arithmetic */
7286 previousroundmode = SCIPintervalGetRoundingMode();
7287 SCIPrationalMultReal(onedivoneminusf0, f0, -1);
7288 SCIPrationalAddReal(onedivoneminusf0, onedivoneminusf0, 1.0);
7289 SCIPrationalInvert(onedivoneminusf0, onedivoneminusf0);
7290
7291 if( SCIPisCertified(scip) )
7292 {
7294 }
7295
7296 rows = SCIPgetLPRows(scip);
7297 currentnegslackrow = 0;
7298 for( i = 0; i < nrowinds; i++ )
7299 {
7300 SCIP_ROW* row;
7301
7302 r = rowinds[i]; /*lint !e613*/
7303 assert(0 <= r && r < SCIPgetNLPRows(scip));
7304 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
7305 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
7306
7307 row = rows[r];
7308 assert(row != NULL);
7309 assert(row->len == 0 || row->cols != NULL);
7310 assert(row->len == 0 || row->cols_index != NULL);
7311 assert(row->len == 0 || row->vals != NULL);
7312
7313 if( slacksign[i] == 1 )
7315 else
7317
7318 /* get the slack's coefficient a'_r = weights[i] * scale in the aggregated row */
7319 SCIPrationalSetReal(ar, weights[i]);
7320 SCIPrationalMultReal(ar, ar, scale);
7321 SCIPrationalMultReal(ar, ar, slacksign[i]);
7322
7323 /* calculate slack variable's coefficient a^_r in the cut */
7324#ifdef SCIP_DISABLED_CODE
7325 if( row->integral && !SCIPisExact(scip)
7326 && ((slacksign[i] == +1 && SCIPisFeasIntegral(scip, row->rhs - row->constant))
7327 || (slacksign[i] == -1 && SCIPisFeasIntegral(scip, row->lhs - row->constant))) ) /*lint !e613*/
7328 {
7329 /* slack variable is always integral:
7330 * a^_r = a~_r = down(a'_r) , if f_r <= f0
7331 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
7332 */
7333 if( !SCIPisExact(scip) )
7334 downar = EPSFLOOR(ar, QUAD_EPSILON);
7335 else
7336 downar = floor(ar);
7337
7338 SCIPquadprecSumDD(fr, ar, -downar);
7339 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) && (!SCIPisExact(scip) || QUAD_TO_DBL(fr) <= QUAD_TO_DBL(f0)) )
7340 {
7341 QUAD_ASSIGN(cutar, downar);
7342 }
7343 else
7344 {
7345 SCIPquadprecSumQQ(cutar, fr, -f0);
7346 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
7347 SCIPquadprecSumQD(cutar, cutar, downar);
7348 }
7349 }
7350 else
7351#endif
7352 {
7353 /* slack variable is continuous:
7354 * a^_r = a~_r = 0 , if a'_r >= 0
7355 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
7356 */
7357 if( !SCIPrationalIsNegative(ar) )
7358 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
7359 else
7360 {
7361 SCIPrationalMult(cutar, ar, onedivoneminusf0); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
7362 }
7363 }
7364
7365 /* if the coefficient was reduced to zero, ignore the slack variable */
7366 if( SCIPrationalIsZero(cutar) )
7367 continue;
7368
7369 /* depending on the slack's sign, we have
7370 * sign = 1: s = rhs - a^Tx >= 0
7371 sign = -1: s = lhs - a^Tx <= 0
7372 */
7373
7374 rowexact = SCIProwGetRowExact(row);
7375 assert(SCIProwExactHasFpRelax(rowexact));
7376 if( SCIProwExactGetRowRhs(rowexact) != NULL && slacksign[i] == 1.0 )
7377 userow = SCIProwExactGetRowRhs(rowexact);
7378 else
7379 userow = row;
7380
7381 {
7382 SCIP_Bool success = TRUE;
7383 SCIP_Real sidevalchg;
7384
7385 SCIPrationalMultReal(cutar, cutar, -slacksign[i]);
7386 if( slacksign[i] == -1 )
7388 else
7390
7391 if( SCIPisCertified(scip) )
7392 {
7393 assert(aggrinfo->negslackweights[currentnegslackrow] == -weights[i]);
7394 aggrinfo->substfactor[currentnegslackrow] = mult;
7395 currentnegslackrow++;
7396 }
7397
7398 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, cutinds, cutcoefs, nnz, userow, mult, &sidevalchg, &success) );
7399 assert(success);
7400
7401 /* move to rhs -> need to round up */
7403 *cutrhs += sidevalchg;
7404 }
7405
7406 /* move slack's constant to the right hand side */
7407 if( slacksign[i] == +1 ) /*lint !e613*/
7408 {
7409 SCIP_INTERVAL valinterval;
7410 SCIP_INTERVAL cutarinterval;
7411
7413 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7414 assert(!SCIPisInfinity(scip, userow->rhs));
7415#ifdef SCIP_DISABLED_CODE
7416 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
7417 if( row->integral )
7418 {
7419 /* the right hand side was implicitly rounded down in row aggregation */
7420 QUAD_ASSIGN(rowrhs, floor(QUAD_TO_DBL(rowrhs)));
7421 }
7422#endif
7423 SCIPintervalSet(&valinterval, userow->rhs);
7424 SCIPintervalSubScalar(SCIPinfinity(scip), &valinterval, valinterval, userow->constant);
7425 SCIPintervalSetRational(&cutarinterval, cutar);
7426 SCIPintervalMul(SCIPinfinity(scip), &valinterval, valinterval, cutarinterval);
7427 SCIPquadprecSumQQ(*cutrhs, *cutrhs, SCIPintervalGetSup(valinterval));
7428 }
7429 else
7430 {
7431 SCIP_INTERVAL valinterval;
7432 SCIP_INTERVAL cutarinterval;
7433
7435 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7436 assert(!SCIPisInfinity(scip, -userow->lhs));
7437#ifdef SCIP_DISABLED_CODE
7438 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
7439 if( row->integral )
7440 {
7441 /* the left hand side was implicitly rounded up in row aggregation */
7442 QUAD_ASSIGN(rowlhs, floor(QUAD_TO_DBL(rowlhs)));
7443 }
7444#endif
7445 SCIPintervalSet(&valinterval, userow->lhs);
7446 SCIPintervalSubScalar(SCIPinfinity(scip), &valinterval, valinterval, userow->constant);
7447 SCIPintervalSetRational(&cutarinterval, cutar);
7448 SCIPintervalMul(SCIPinfinity(scip), &valinterval, valinterval, cutarinterval);
7449 SCIPquadprecSumQQ(*cutrhs, *cutrhs, SCIPintervalGetSup(valinterval));
7450 }
7451 }
7452
7453 /* relax rhs to zero, if it's very close to 0 */
7454 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
7455 QUAD_ASSIGN(*cutrhs, 0.0);
7456
7457 if( SCIPisExact(scip) )
7458 SCIPintervalSetRoundingMode(previousroundmode);
7459
7462
7463 SCIPrationalFreeBuffer(SCIPbuffer(scip), &onedivoneminusf0);
7464 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
7465
7466 return SCIP_OKAY;
7467}
7468#endif
7469
7470/** substitute aggregated slack variables:
7471 *
7472 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
7473 * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
7474 *
7475 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
7476 * \f[
7477 * \begin{array}{rll}
7478 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
7479 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
7480 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
7481 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
7482 * \end{array}
7483 * \f]
7484 *
7485 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
7486 */
7487static
7489 SCIP* scip, /**< SCIP data structure */
7490 SCIP_Real* weights, /**< row weights in row summation */
7491 int* slacksign, /**< stores the sign of the row's slack variable in summation */
7492 int* rowinds, /**< sparsity pattern of used rows */
7493 int nrowinds, /**< number of used rows */
7494 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
7495 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7496 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
7497 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7498 int* nnz, /**< number of non-zeros in cut */
7499 QUAD(SCIP_Real f0) /**< fractional value of rhs */
7500 )
7501{ /*lint --e{715}*/
7502 SCIP_ROW** rows;
7503 SCIP_Real QUAD(onedivoneminusf0);
7504 int i;
7505
7506 assert(scip != NULL);
7507 assert(weights != NULL || nrowinds == 0);
7508 assert(slacksign != NULL || nrowinds == 0);
7509 assert(rowinds != NULL || nrowinds == 0);
7510 assert(scale > 0.0);
7511 assert(cutcoefs != NULL);
7512 assert(QUAD_HI(cutrhs) != NULL);
7513 assert(cutinds != NULL);
7514 assert(nnz != NULL);
7515 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
7517
7518 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
7519 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
7520
7521 rows = SCIPgetLPRows(scip);
7522 for( i = 0; i < nrowinds; i++ )
7523 {
7524 SCIP_ROW* row;
7525 SCIP_Real QUAD(ar);
7526 SCIP_Real QUAD(downar);
7527 SCIP_Real QUAD(cutar);
7528 SCIP_Real QUAD(fr);
7529 SCIP_Real QUAD(tmp);
7530 SCIP_Real QUAD(myprod);
7531 int r;
7532
7533 r = rowinds[i]; /*lint !e613*/
7534 assert(0 <= r && r < SCIPgetNLPRows(scip));
7535 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
7536 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
7537
7538 row = rows[r];
7539 assert(row != NULL);
7540 assert(row->len == 0 || row->cols != NULL);
7541 assert(row->len == 0 || row->cols_index != NULL);
7542 assert(row->len == 0 || row->vals != NULL);
7543
7544 /* get the slack's coefficient a'_r in the aggregated row */
7545 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
7546
7547 /* calculate slack variable's coefficient a^_r in the cut */
7548 if( row->integral )
7549 {
7550 /* slack variable is always integral:
7551 * a^_r = a~_r = down(a'_r) , if f_r <= f0
7552 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
7553 */
7554 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
7555 SCIPquadprecSumQQ(fr, ar, -downar);
7556 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
7557
7558 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
7559 QUAD_ASSIGN_Q(cutar, downar); /* a^_r */
7560 else
7561 {
7562 SCIPquadprecSumQQ(cutar, fr, -f0);
7563 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
7564 SCIPquadprecSumQQ(cutar, cutar, downar);
7565 }
7566 }
7567 else
7568 {
7569 /* slack variable is continuous:
7570 * a^_r = a~_r = 0 , if a'_r >= 0
7571 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
7572 */
7573 if( QUAD_TO_DBL(ar) >= 0.0 )
7574 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
7575 else
7576 SCIPquadprecProdQQ(cutar, onedivoneminusf0, ar);
7577 }
7578
7579 /* if the coefficient was reduced to zero, ignore the slack variable */
7580 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
7581 continue;
7582
7583 /* depending on the slack's sign, we have
7584 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
7585 * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
7586 */
7587 SCIPquadprecProdQD(myprod, cutar, -slacksign[i]);
7588
7589 /* add the slack's definition multiplied with a^_j to the cut */
7590 SCIP_CALL( varVecAddScaledRowCoefsQuadScale(cutinds, cutcoefs, nnz, row, QUAD(myprod)) );
7591
7592 /* move slack's constant to the right hand side */
7593 if( slacksign[i] == +1 ) /*lint !e613*/
7594 {
7595 SCIP_Real QUAD(rowrhs);
7596
7597 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7598 assert(!SCIPisInfinity(scip, row->rhs));
7599 QUAD_ASSIGN(rowrhs, row->rhs - row->constant);
7600 if( row->integral )
7601 {
7602 /* the right hand side was implicitly rounded down in row aggregation */
7603 SCIPquadprecEpsFloorQ(rowrhs, rowrhs, SCIPepsilon(scip)); /*lint !e666*/
7604 }
7605 SCIPquadprecProdQQ(tmp, myprod, rowrhs);
7606 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
7607 }
7608 else
7609 {
7610 SCIP_Real QUAD(rowlhs);
7611
7612 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7613 assert(!SCIPisInfinity(scip, -row->lhs));
7614 QUAD_ASSIGN(rowlhs, row->lhs - row->constant);
7615 if( row->integral )
7616 {
7617 /* the left hand side was implicitly rounded up in row aggregation */
7618 SCIPquadprecEpsCeilQ(rowlhs, rowlhs, SCIPepsilon(scip)); /*lint !e666*/
7619 }
7620 SCIPquadprecProdQQ(tmp, myprod, rowlhs);
7621 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
7622 }
7623 }
7624
7625 /* relax rhs to zero, if it's very close to 0 */
7626 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
7627 QUAD_ASSIGN(*cutrhs, 0.0);
7628
7629 return SCIP_OKAY;
7630}
7631
7632/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
7633 * these rows cannot participate in an MIR cut.
7634 *
7635 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7636 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7637 *
7638 * @pre This method can be called if @p scip is in one of the following stages:
7639 * - \ref SCIP_STAGE_SOLVING
7640 *
7641 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
7642 *
7643 * @note this method is safe for usage in exact solving mode
7644 *
7645 * @todo make behavior identical to the unsafe MIR cut computation
7646 */
7647static
7649 SCIP* scip, /**< SCIP data structure */
7650 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7651 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
7652 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
7653 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
7654 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7655 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
7656 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
7657 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
7658 * NULL for using closest bound for all variables */
7659 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
7660 * NULL for using closest bound for all variables */
7661 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
7662 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
7663 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
7664 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
7665 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
7666 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
7667 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
7668 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
7669 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
7670 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
7671 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
7672 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
7673 )
7674{
7675 int i;
7676 int nvars;
7677 int tmpnnz;
7678 int* varsign;
7679 int* boundtype;
7680 int* tmpinds;
7681 SCIP_Real* tmpcoefs;
7682
7683 SCIP_Real rhs;
7684 SCIP_Real downrhs;
7685 SCIP_Bool freevariable;
7686 SCIP_Bool localbdsused;
7687 SCIP_Bool tmpislocal;
7688
7689 SCIP_ROUNDMODE previousroundmode;
7690 SCIP_INTERVAL f0interval;
7691
7692 assert(aggrrow != NULL);
7693 assert(SCIPisPositive(scip, scale));
7695 assert(success != NULL);
7696
7697 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
7698
7699 *success = FALSE;
7700 *cutislocal = FALSE;
7701
7702 /* allocate temporary memory */
7705 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
7708
7709 /* initialize cut with aggregation */
7710 tmpnnz = aggrrow->nnz;
7711 tmpislocal = aggrrow->local;
7712
7713 previousroundmode = SCIPintervalGetRoundingMode();
7715
7716 if( SCIPisCertified(scip) )
7717 {
7719 }
7720
7721 rhs = QUAD_TO_DBL(aggrrow->rhs) * scale;
7722
7723 if( tmpnnz > 0 )
7724 {
7725 BMScopyMemoryArray(tmpinds, aggrrow->inds, tmpnnz);
7726
7727 for( i = 0; i < tmpnnz; ++i )
7728 {
7729 SCIP_Real coef;
7730 int k = aggrrow->inds[i];
7731
7732 coef = aggrrow->vals[k];
7733 coef *= scale;
7734 tmpcoefs[k] = coef;
7735
7736 assert(coef != 0.0);
7737 }
7738
7739 SCIPdebugMsg(scip, "Initial row:\n");
7740 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
7741
7742 /* Transform equation a*x == b, lb <= x <= ub into standard form
7743 * a'*x' == b, 0 <= x' <= ub'.
7744 *
7745 * Transform variables (lb or ub):
7746 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
7747 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
7748 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
7749 *
7750 * Transform variables (vlb or vub):
7751 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
7752 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
7753 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
7754 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
7755 * a_{zu_j} := a_{zu_j} + a_j * bu_j
7756 */
7757 SCIP_CALL( cutsTransformMIRSafely(scip, sol, boundswitch, usevbds, allowlocal, fixintegralrhs, FALSE,
7758 boundsfortrans, boundtypesfortrans, tmpcoefs, &rhs, tmpinds, &tmpnnz, varsign, boundtype, &freevariable, &localbdsused) );
7759 assert(allowlocal || !localbdsused);
7760 tmpislocal = tmpislocal || localbdsused;
7761
7762 if( freevariable )
7763 goto TERMINATE;
7764
7765 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
7766 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
7767 }
7768
7769 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
7770 * a~*x' <= down(b)
7771 * integers : a~_j = down(a'_j) , if f_j <= f_0
7772 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
7773 * continuous: a~_j = 0 , if a'_j >= 0
7774 * a~_j = a'_j/(1 - f0) , if a'_j < 0
7775 *
7776 * Transform inequality back to a^*x <= rhs:
7777 *
7778 * (lb or ub):
7779 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
7780 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
7781 * and move the constant terms
7782 * -a~_j * lb_j == -a^_j * lb_j, or
7783 * a~_j * ub_j == -a^_j * ub_j
7784 * to the rhs.
7785 *
7786 * (vlb or vub):
7787 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
7788 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
7789 * move the constant terms
7790 * -a~_j * dl_j == -a^_j * dl_j, or
7791 * a~_j * du_j == -a^_j * du_j
7792 * to the rhs, and update the VB variable coefficients:
7793 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
7794 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
7795 */
7796
7797 downrhs = floor(rhs);
7798
7799 if( SCIPisCertified(scip) )
7800 {
7802 SCIPrationalSetReal(mirinfo->rhs, downrhs);
7803 SCIPrationalSetReal(mirinfo->frac, rhs);
7804 SCIPrationalDiffReal(mirinfo->frac, mirinfo->frac, downrhs);
7805 }
7806
7807 SCIPintervalSet(&f0interval, rhs);
7808 SCIPintervalSubScalar(SCIPinfinity(scip), &f0interval, f0interval, downrhs);
7809
7810 if( f0interval.inf < minfrac || f0interval.sup > maxfrac )
7811 goto TERMINATE;
7812
7813 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
7814 * If this gives a scalar that is very big, we better do not generate this cut.
7815 */
7816 if( REALABS(scale)/(1.0 - f0interval.inf) > MAXCMIRSCALE )
7817 goto TERMINATE;
7818
7819 /* renormalize f0 value */
7820 rhs = downrhs;
7821
7822 if( tmpnnz > 0 )
7823 {
7824 SCIP_CALL( cutsRoundMIRSafely(scip, tmpcoefs, &rhs, tmpinds, &tmpnnz, varsign, boundtype, f0interval) ); /*lint !e644*/
7825
7826 SCIPdebugMsg(scip, "After MIR rounding:\n");
7827 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
7828 }
7829
7830 /* substitute aggregated slack variables:
7831 *
7832 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
7833 * variable only appears in its own row:
7834 * a'_r = scale * weight[r] * slacksign[r].
7835 *
7836 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
7837 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
7838 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
7839 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
7840 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
7841 *
7842 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
7843 */
7844
7845 SCIP_CALL( cutsSubstituteMIRSafely(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
7846 aggrrow->nrows, scale, tmpcoefs, &rhs, tmpinds, &tmpnnz, f0interval) );
7847
7848 SCIPdebugMsg(scip, "After slack substitution:\n");
7849 SCIPdebug( printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE) );
7850
7851 /* we work on rhs -> round up */
7853
7854 if( postprocess )
7855 {
7856 SCIP_CALL( postprocessCutSafely(scip, tmpislocal, tmpinds, tmpcoefs, &tmpnnz, &rhs, success) );
7857 }
7858 else
7859 {
7860 *success = !removeZerosSafely(scip, SCIPsumepsilon(scip), tmpcoefs, &rhs, tmpinds, &tmpnnz);
7861 }
7862
7863 SCIPdebugMsg(scip, "After post processing:\n");
7864 SCIPdebug( printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE) );
7865
7866 if( *success )
7867 {
7868 SCIP_Real mirefficacy = calcEfficacyDenseStorage(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz);
7869
7870 if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
7871 {
7872 BMScopyMemoryArray(cutinds, tmpinds, tmpnnz);
7873 *cutnnz = tmpnnz;
7874 *cutrhs = rhs;
7875 *cutislocal = tmpislocal;
7876
7877 /* clean tmpcoefs and go back to double precision */
7878 for( i = 0; i < *cutnnz; ++i )
7879 {
7880 int j = cutinds[i];
7881
7882 cutcoefs[i] = tmpcoefs[j];
7883 tmpcoefs[j] = 0.0;
7884 }
7885
7886 if( cutefficacy != NULL )
7887 *cutefficacy = mirefficacy;
7888
7889 if( cutrank != NULL )
7890 *cutrank = aggrrow->rank + 1;
7891 }
7892 else
7893 {
7894 *success = FALSE;
7895 }
7896 }
7897
7898 TERMINATE:
7899
7900 /* reset the rounding mode in exact mode */
7901 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
7902
7903 if( !(*success) )
7904 {
7905 for( i = 0; i < tmpnnz; ++i )
7906 {
7907 tmpcoefs[tmpinds[i]] = 0.0;
7908 }
7909 }
7910
7911 /* free temporary memory */
7912 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
7913 SCIPfreeBufferArray(scip, &tmpinds);
7914 SCIPfreeBufferArray(scip, &boundtype);
7915 SCIPfreeBufferArray(scip, &varsign);
7916
7917 return SCIP_OKAY;
7918}
7919
7920
7921/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
7922 * these rows cannot participate in an MIR cut.
7923 *
7924 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7925 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7926 *
7927 * @pre This method can be called if @p scip is in one of the following stages:
7928 * - \ref SCIP_STAGE_SOLVING
7929 *
7930 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
7931 *
7932 * @note this method is safe for usage in exact solving mode
7933 */
7935 SCIP* scip, /**< SCIP data structure */
7936 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7937 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
7938 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
7939 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
7940 * type substitution is allowed. The indices are: 0: continuous,
7941 * 1: continuous implint., 2: integer implint, 3: binary implint,
7942 * 4: integer, 5: binary */
7943 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7944 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
7945 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
7946 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
7947 * NULL for using closest bound for all variables */
7948 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
7949 * NULL for using closest bound for all variables */
7950 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
7951 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
7952 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
7953 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
7954 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
7955 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
7956 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
7957 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
7958 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
7959 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
7960 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
7961 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
7962 )
7963{
7964 MIR_DATA* data;
7965 int* varsign;
7966 int* boundtype;
7967 SCIP_Real QUAD(downrhs);
7968 SCIP_Real QUAD(f0);
7969 SCIP_Bool freevariable;
7970 SCIP_Bool localbdsused;
7971 SCIP_Bool tmpislocal;
7972
7973 assert(aggrrow != NULL);
7974 assert(SCIPisPositive(scip, scale));
7975 assert(success != NULL);
7976
7977 if( SCIPisExact(scip) )
7978 {
7979 /* TODO: update exactSCIP cuts to behave identically with respect to implied integrality */
7980 return calcMIRSafely(scip, sol, postprocess, boundswitch, vartypeusevbds > 0 ? TRUE : FALSE, allowlocal, fixintegralrhs,
7981 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, scale, aggrrow, cutcoefs, cutrhs,
7982 cutinds, cutnnz, cutefficacy, cutrank, cutislocal, success);
7983 }
7984 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
7985
7986 *success = FALSE;
7987
7988 /* Setup data to track cut and initialize the cut with aggregation */
7989 int l;
7990 int nnz;
7991
7992 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
7993
7994 SCIP_CALL( SCIPallocBuffer(scip, &data) );
7995
7996 nnz = aggrrow->nnz;
7997 data->totalnnz = nnz;
7998
7999 /* initialize sections */
8000 for( l = 0; l < NSECTIONS; ++l )
8001 {
8002 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
8003 data->secnnz[l] = 0;
8004 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
8005 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
8006 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
8007 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
8008 /* Use variable bounds for the sections specified by the user */
8009 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
8010 }
8011
8012 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
8013 data->vars = SCIPgetVars(scip);
8014 data->nvars = SCIPgetNVars(scip);
8015 data->nbinvars = SCIPgetNBinVars(scip);
8016 data->nintvars = SCIPgetNIntVars(scip);
8021
8023 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
8024
8025 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, scale);
8026
8027 if( nnz > 0 )
8028 {
8029 /* Initalize cut with the aggregation */
8030 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
8031
8032 for( l = 0; l < nnz; ++l )
8033 {
8034 SCIP_Real QUAD(coef);
8035 int m = aggrrow->inds[l];
8036
8037 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
8038
8039 SCIPquadprecProdQD(coef, coef, scale);
8040
8041 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
8042
8043 assert(QUAD_HI(coef) != 0.0);
8044 }
8045
8046 /* Sort the array by problem index and add the variables to their sections */
8047 SCIPsortDownInt(data->cutinds, nnz);
8048 for( l = 0; l < nnz; ++l )
8049 {
8050 int section = varSection(data, data->cutinds[l]);
8051 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
8052 ++data->secnnz[section];
8053 }
8054 }
8055
8056 SCIPdebugMsg(scip, "Initial row:\n");
8057 SCIPdebug( printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, nnz, FALSE, FALSE) );
8058
8059 data->ncutinds = 0;
8060 tmpislocal = aggrrow->local;
8061
8062 /* allocate temporary memory */
8063 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, data->nvars) );
8064 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, data->nvars) );
8065
8066 /* Transform equation a*x == b, lb <= x <= ub into standard form
8067 * a'*x' == b, 0 <= x' <= ub'.
8068 *
8069 * Transform variables (lb or ub):
8070 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
8071 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
8072 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
8073 *
8074 * Transform variables (vlb or vub):
8075 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
8076 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
8077 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
8078 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
8079 * a_{zu_j} := a_{zu_j} + a_j * bu_j
8080 */
8081 if( data->totalnnz > 0 )
8082 {
8083 SCIP_CALL( cutsTransformMIR(scip, data, sol, boundswitch, allowlocal, fixintegralrhs, FALSE,
8084 boundsfortrans, boundtypesfortrans, minfrac, maxfrac,
8085 varsign, boundtype, &freevariable, &localbdsused) );
8086 assert(allowlocal || !localbdsused);
8087 tmpislocal = tmpislocal || localbdsused;
8088
8089 if( freevariable )
8090 goto TERMINATE;
8091
8092 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
8093 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
8094 }
8095
8096 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
8097 * a~*x' <= down(b)
8098 * integers : a~_j = down(a'_j) , if f_j <= f_0
8099 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
8100 * continuous: a~_j = 0 , if a'_j >= 0
8101 * a~_j = a'_j/(1 - f0) , if a'_j < 0
8102 *
8103 * Transform inequality back to a^*x <= rhs:
8104 *
8105 * (lb or ub):
8106 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
8107 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
8108 * and move the constant terms
8109 * -a~_j * lb_j == -a^_j * lb_j, or
8110 * a~_j * ub_j == -a^_j * ub_j
8111 * to the rhs.
8112 *
8113 * (vlb or vub):
8114 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
8115 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
8116 * move the constant terms
8117 * -a~_j * dl_j == -a^_j * dl_j, or
8118 * a~_j * du_j == -a^_j * du_j
8119 * to the rhs, and update the VB variable coefficients:
8120 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
8121 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
8122 */
8123
8124 SCIPquadprecEpsFloorQ(downrhs, data->cutrhs, SCIPepsilon(scip)); /*lint !e666*/
8125 SCIPquadprecSumQQ(f0, data->cutrhs, -downrhs);
8126 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
8127
8128 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
8129 goto TERMINATE;
8130
8131 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
8132 * If this gives a scalar that is very big, we better do not generate this cut.
8133 */
8134 if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
8135 goto TERMINATE;
8136
8137 /* renormalize f0 value */
8138 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
8139
8140 QUAD_ASSIGN_Q(data->cutrhs, downrhs);
8141
8142 if( data->totalnnz > 0 )
8143 {
8144 SCIP_CALL( cutsRoundMIR(scip, data, varsign, boundtype, QUAD(f0)) );
8145
8146 SCIPdebugMsg(scip, "After MIR rounding:\n");
8147 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
8148 }
8149
8150 /* substitute aggregated slack variables:
8151 *
8152 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
8153 * variable only appears in its own row:
8154 * a'_r = scale * weight[r] * slacksign[r].
8155 *
8156 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
8157 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
8158 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
8159 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
8160 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
8161 *
8162 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
8163 */
8164 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
8165 aggrrow->nrows, scale,
8166 data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds, QUAD(f0)) );
8167
8168 SCIPdebugMsg(scip, "After slack substitution:\n");
8169 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
8170
8171 if( postprocess )
8172 {
8173 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
8174 * prevent numerical rounding errors
8175 */
8176 SCIP_CALL( postprocessCutQuad(scip, tmpislocal, data->cutinds, data->cutcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
8177 }
8178 else
8179 {
8180 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), tmpislocal, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds);
8181 }
8182
8183 SCIPdebugMsg(scip, "After post processing:\n");
8184 SCIPdebug( printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE) );
8185
8186 if( *success )
8187 {
8188 SCIP_Real mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, data->cutcoefs, QUAD_TO_DBL(data->cutrhs), data->cutinds, data->ncutinds);
8189
8190 if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
8191 {
8192 BMScopyMemoryArray(cutinds, data->cutinds, data->ncutinds);
8193 *cutnnz = data->ncutinds;
8194 *cutrhs = QUAD_TO_DBL(data->cutrhs);
8195 *cutislocal = tmpislocal;
8196
8197 /* clean tmpcoefs and go back to double precision */
8198 for(int i = 0; i < *cutnnz; ++i )
8199 {
8200 SCIP_Real QUAD(coef);
8201 int j = cutinds[i];
8202
8203 QUAD_ARRAY_LOAD(coef, data->cutcoefs, j);
8204
8205 cutcoefs[i] = QUAD_TO_DBL(coef);
8206 QUAD_ASSIGN(coef, 0.0);
8207 QUAD_ARRAY_STORE(data->cutcoefs, j, coef);
8208 }
8209
8210 if( cutefficacy != NULL )
8211 *cutefficacy = mirefficacy;
8212
8213 if( cutrank != NULL )
8214 *cutrank = aggrrow->rank + 1;
8215 }
8216 else
8217 {
8218 *success = FALSE;
8219 }
8220 }
8221
8222 TERMINATE:
8223 if( !(*success) )
8224 {
8225 SCIP_Real QUAD(tmp);
8226
8227 QUAD_ASSIGN(tmp, 0.0);
8228 for(int i = 0; i < data->ncutinds; ++i )
8229 {
8230 QUAD_ARRAY_STORE(data->cutcoefs, data->cutinds[i], tmp);
8231 }
8232 }
8233
8234#ifndef NDEBUG
8235 for( int i = 0; i < QUAD_ARRAY_SIZE(data->nvars); ++i )
8236 {
8237 if(data->cutcoefs[i] != 0.0)
8238 {
8239 SCIPdebugMsg(scip, "coefs have not been reset\n");
8240 SCIPABORT();
8241 }
8242 }
8243#endif
8244
8245 SCIPfreeBufferArray(scip, &boundtype);
8246 SCIPfreeBufferArray(scip, &varsign);
8247
8248 if( data->cutinds != NULL )
8250
8251 if( data->cutcoefs != NULL )
8253
8254 for( int s = NSECTIONS - 1; s >= 0; --s )
8255 {
8257 }
8258
8259 SCIPfreeBuffer(scip, &data);
8260
8261 return SCIP_OKAY;
8262}
8263
8264/** compute the efficacy of the MIR cut for the given values without computing the cut.
8265 * This is used for the CMIR cut generation heuristic.
8266 */
8267static
8269 SCIP* scip, /**< SCIP datastructure */
8270 SCIP_Real*RESTRICT coefs, /**< array with coefficients in row */
8271 SCIP_Real*RESTRICT solvals, /**< solution values of variables in the row */
8272 SCIP_Real rhs, /**< right hand side of MIR cut */
8273 SCIP_Real contactivity, /**< aggregated activity of continuous variables in the row */
8274 SCIP_Real contsqrnorm, /**< squared norm of continuous variables */
8275 SCIP_Real delta, /**< delta value to compute the violation for */
8276 int nvars, /**< number of variables in the row, i.e. the size of coefs and solvals arrays */
8277 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
8278 SCIP_Real maxfrac /**< maximal fractionality of rhs to produce MIR cut for */
8279 )
8280{
8281 int i;
8282 SCIP_Real f0pluseps;
8283 SCIP_Real f0;
8284 SCIP_Real onedivoneminusf0;
8285 SCIP_Real scale;
8286 SCIP_Real downrhs;
8287 SCIP_Real norm;
8288 SCIP_Real contscale;
8289
8290 scale = 1.0 / delta;
8291 rhs *= scale;
8292 downrhs = SCIPfloor(scip, rhs);
8293 f0 = rhs - downrhs;
8294
8295 if( f0 < minfrac || f0 > maxfrac )
8296 return 0.0;
8297
8298 onedivoneminusf0 = 1.0 / (1.0 - f0);
8299
8300 contscale = scale * onedivoneminusf0;
8301
8302 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
8303 * If this gives a scalar that is very big, we better do not generate this cut.
8304 */
8305 if( contscale > MAXCMIRSCALE )
8306 return 0.0;
8307
8308 rhs = downrhs;
8309 rhs -= contscale * contactivity;
8310 norm = SQR(contscale) * contsqrnorm;
8311
8312 assert(!SCIPisFeasZero(scip, f0));
8313 assert(!SCIPisFeasZero(scip, 1.0 - f0));
8314
8315 f0pluseps = f0 + SCIPepsilon(scip);
8316
8317 for( i = 0; i < nvars; ++i )
8318 {
8319 SCIP_Real floorai = SCIPfloor(scip, scale * coefs[i]);
8320 SCIP_Real fi = (scale * coefs[i]) - floorai;
8321
8322 if( fi > f0pluseps )
8323 floorai += (fi - f0) * onedivoneminusf0;
8324
8325 rhs -= solvals[i] * floorai;
8326 norm += SQR(floorai);
8327 }
8328
8329 norm = sqrt(norm);
8330
8331 return - rhs / MAX(norm, 1e-6);
8332}
8333
8334/** calculates an MIR cut out of an aggregation of LP rows
8335 *
8336 * Given the aggregation, it is transformed to a mixed knapsack set via complementation (using bounds or variable bounds)
8337 * Then, different scalings of the mkset are used to generate a MIR and the best is chosen.
8338 * One of the steps of the MIR is to round the coefficients of the integer variables down,
8339 * so one would prefer to have integer coefficients for integer variables which are far away from their bounds in the
8340 * mkset.
8341 *
8342 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8343 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8344 *
8345 * @pre This method can be called if @p scip is in one of the following stages:
8346 * - \ref SCIP_STAGE_SOLVING
8347 *
8348 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
8349 */
8351 SCIP* scip, /**< SCIP data structure */
8352 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8353 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
8354 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
8355 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
8356 * type substitution is allowed. The indices are: 0: continuous,
8357 * 1: continuous implint., 2: integer implint, 3: binary implint,
8358 * 4: integer, 5: binary */
8359 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8360 int maxtestdelta, /**< maximum number of deltas to test */
8361 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
8362 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
8363 * NULL for using closest bound for all variables */
8364 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
8365 * NULL for using closest bound for all variables */
8366 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
8367 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
8368 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
8369 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
8370 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
8371 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
8372 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
8373 SCIP_Real* cutefficacy, /**< pointer to store efficacy of best cut; only cuts that are strictly better than the value of
8374 * this efficacy on input to this function are returned */
8375 int* cutrank, /**< pointer to return rank of generated cut (or NULL) */
8376 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
8377 SCIP_Bool* success /**< pointer to store whether a valid and efficacious cut was returned */
8378 )
8379{
8380 int i;
8381 int firstcontvar;
8382 int nvars;
8383 int intstart;
8384 int ntmpcoefs;
8385 int* varsign;
8386 int* boundtype;
8387 int* mksetinds;
8388 SCIP_Real* mksetcoefs;
8389 SCIP_Real QUAD(mksetrhs);
8390 int mksetnnz;
8391 SCIP_Real* bounddist;
8392 int* bounddistpos;
8393 int nbounddist;
8394 SCIP_Real* tmpcoefs;
8395 SCIP_Real* tmpvalues;
8396 SCIP_Real* deltacands;
8397 int ndeltacands;
8398 SCIP_Real bestdelta;
8399 SCIP_Real bestefficacy;
8400 SCIP_Real maxabsmksetcoef;
8401 SCIP_VAR** vars;
8402 SCIP_Bool freevariable;
8403 SCIP_Bool localbdsused;
8404 SCIP_Real contactivity;
8405 SCIP_Real contsqrnorm;
8406 MIR_DATA* data;
8407
8408 assert(aggrrow != NULL);
8409 assert(aggrrow->nrows + aggrrow->nnz >= 1);
8410 assert(success != NULL);
8411
8412 *success = FALSE;
8416
8417 /* allocate temporary memory */
8419 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
8420
8421 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, nvars + aggrrow->nrows) );
8422 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars + aggrrow->nrows) );
8423 /* The +4 comes from a few rules that create extra delta candidates, see usages of ndeltacands. */
8424 SCIP_CALL( SCIPallocBufferArray(scip, &deltacands, nvars + 4) );
8425
8426 /* we only compute bound distance for integer variables; by variable bound substitution, the number of integer variables
8427 * can grow significantly. Hence, these allocations are length nvars */
8428 SCIP_CALL( SCIPallocBufferArray(scip, &bounddist, nvars) );
8429 SCIP_CALL( SCIPallocBufferArray(scip, &bounddistpos, nvars) );
8430
8431 /* initialize mkset with the unscaled aggregation */
8432 {
8433 int l;
8434 int nnz;
8435
8436 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
8437
8438 SCIP_CALL( SCIPallocBuffer(scip, &data) );
8439
8440 nnz = aggrrow->nnz;
8441 data->totalnnz = nnz;
8442
8443 /* initialize sections */
8444 for( l = 0; l < NSECTIONS; ++l )
8445 {
8446 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
8447 data->secnnz[l] = 0;
8448 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
8449 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
8450 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
8451 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
8452 /* Use variable bounds for the sections specified by the user */
8453 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
8454 }
8455
8456 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
8457 data->vars = SCIPgetVars(scip);
8458 data->nvars = SCIPgetNVars(scip);
8459 data->nbinvars = SCIPgetNBinVars(scip);
8460 data->nintvars = SCIPgetNIntVars(scip);
8465
8467 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
8468
8469 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, 1.0);
8470
8471 if( nnz > 0 )
8472 {
8473 /* Initalize cut with the aggregation */
8474 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
8475
8476 for( l = 0; l < nnz; ++l )
8477 {
8478 SCIP_Real QUAD(coef);
8479 int m = aggrrow->inds[l];
8480
8481 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
8482
8483 SCIPquadprecProdQD(coef, coef, 1.0);
8484
8485 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
8486
8487 assert(QUAD_HI(coef) != 0.0);
8488 }
8489
8490 /* Sort the array by problem index and add the variables to their sections */
8491 SCIPsortDownInt(data->cutinds, nnz);
8492 for( l = 0; l < nnz; ++l )
8493 {
8494 int section = varSection(data, data->cutinds[l]);
8495 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
8496 ++data->secnnz[section];
8497 }
8498 }
8499
8500 data->ncutinds = 0;
8501 }
8502 *cutislocal = aggrrow->local;
8503
8504 /* Transform equation a*x == b, lb <= x <= ub into standard form
8505 * a'*x' == b, 0 <= x' <= ub'.
8506 *
8507 * Transform variables (lb or ub):
8508 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
8509 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
8510 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
8511 *
8512 * Transform variables (vlb or vub):
8513 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
8514 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
8515 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
8516 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
8517 * a_{zu_j} := a_{zu_j} + a_j * bu_j
8518 */
8519 SCIP_CALL( cutsTransformMIR(scip, data, sol, boundswitch, allowlocal, FALSE, FALSE,
8520 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, varsign, boundtype, &freevariable, &localbdsused) );
8521 assert(allowlocal || !localbdsused);
8522
8523 /* Use aliases to stay more consistent with the old code. mksetrhs needs to synchronize its values data->cutrhs
8524 * again before calling SCIProundMIR()! */
8525 mksetinds = data->cutinds;
8526 mksetcoefs = data->cutcoefs;
8527 mksetnnz = data->ncutinds;
8528 QUAD_ASSIGN_Q(mksetrhs, data->cutrhs);
8529
8530 if( freevariable )
8531 goto TERMINATE;
8532
8533 SCIPdebugMsg(scip, "transformed aggrrow row:\n");
8534 SCIPdebug( printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE) );
8535
8536 /* found positions of integral variables that are strictly between their bounds */
8537 maxabsmksetcoef = -1.0;
8538 nbounddist = 0;
8539
8540 assert(mksetnnz <= nvars);
8541 for( i = mksetnnz - 1; i >= 0 && mksetinds[i] < firstcontvar; --i )
8542 {
8543 SCIP_VAR* var = vars[mksetinds[i]];
8547 SCIP_Real QUAD(coef);
8548
8549 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
8550
8551 if( SCIPisEQ(scip, primsol, lb) || SCIPisEQ(scip, primsol, ub) )
8552 continue;
8553
8554 bounddist[nbounddist] = MIN(ub - primsol, primsol - lb);
8555 bounddistpos[nbounddist] = i;
8556 deltacands[nbounddist] = QUAD_TO_DBL(coef);
8557 ++nbounddist;
8558 }
8559 assert(nbounddist <= nvars);
8560
8561 /* no fractional variable; so abort here */
8562 if( nbounddist == 0 )
8563 goto TERMINATE;
8564
8565 intstart = i + 1;
8566
8567 /* Check that the continuous and implied integer variables and integer variables are partitioned */
8568#ifndef NDEBUG
8569 for( int j = 0; j < intstart; ++j )
8570 {
8572 }
8573 for( int j = intstart; j < data->ncutinds; ++j )
8574 {
8575 assert(SCIPvarIsIntegral(vars[mksetinds[j]]));
8576 }
8577#endif
8578
8579 ndeltacands = nbounddist;
8580 assert(ndeltacands <= nvars);
8581 SCIPsortDownRealRealInt(bounddist, deltacands, bounddistpos, nbounddist);
8582
8583 {
8584 SCIP_Real intscale;
8585 SCIP_Bool intscalesuccess;
8586
8587 SCIP_CALL( SCIPcalcIntegralScalar(deltacands, nbounddist, -SCIPepsilon(scip), SCIPsumepsilon(scip), (SCIP_Longint)10000, 10000.0, &intscale, &intscalesuccess) );
8588
8589 if( intscalesuccess )
8590 {
8591 SCIP_Real intf0;
8592 SCIP_Real intscalerhs;
8593 SCIP_Real delta;
8594
8595 intscalerhs = QUAD_TO_DBL(data->cutrhs) * intscale;
8596 delta = 1.0 / intscale;
8597 intf0 = intscalerhs - floor(intscalerhs);
8598
8599 if( ! SCIPisFeasIntegral(scip, intf0) )
8600 {
8601 if( intf0 < minfrac || intf0 > maxfrac )
8602 {
8603 intscale *= SCIPceil(scip, MAX(minfrac, (1.0 - maxfrac)) / MIN(intf0, (1.0 - intf0)));
8604 intscalerhs = QUAD_TO_DBL(data->cutrhs) * intscale;
8605 delta = 1.0 / intscale;
8606 intf0 = intscalerhs - floor(intscalerhs);
8607 }
8608
8609 if( intf0 >= minfrac && intf0 <= maxfrac )
8610 {
8611 if( ! SCIPisEQ(scip, delta, 1.0) )
8612 deltacands[ndeltacands++] = delta;
8613
8614 if( intf0 < maxfrac )
8615 {
8616 SCIP_Real delta2;
8617
8618 delta2 = 1.0 / (intscale * SCIPfloor(scip, maxfrac / intf0));
8619
8620 if( ! SCIPisEQ(scip, delta, delta2) && ! SCIPisEQ(scip, delta2, 1.0) )
8621 deltacands[ndeltacands++] = delta2;
8622 }
8623 }
8624 }
8625 }
8626 }
8627
8628 for( i = 0; i < nbounddist; ++i )
8629 {
8630 SCIP_Real absmksetcoef;
8631
8632 absmksetcoef = REALABS(deltacands[i]);
8633 maxabsmksetcoef = MAX(absmksetcoef, maxabsmksetcoef);
8634
8635 deltacands[i] = absmksetcoef;
8636 }
8637
8638 /* also test 1.0 and maxabsmksetcoef + 1.0 as last delta values */
8639 if( maxabsmksetcoef != -1.0 )
8640 deltacands[ndeltacands++] = maxabsmksetcoef + 1.0;
8641
8642 deltacands[ndeltacands++] = 1.0;
8643
8644 maxtestdelta = MIN(ndeltacands, maxtestdelta);
8645
8646 /* For each delta
8647 * Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
8648 * a~*x' <= down(b)
8649 * integers : a~_j = down(a'_j) , if f_j <= f_0
8650 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
8651 * continuous: a~_j = 0 , if a'_j >= 0
8652 * a~_j = a'_j/(1 - f0) , if a'_j < 0
8653 *
8654 * Transform inequality back to a^*x <= rhs:
8655 *
8656 * (lb or ub):
8657 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
8658 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
8659 * and move the constant terms
8660 * -a~_j * lb_j == -a^_j * lb_j, or
8661 * a~_j * ub_j == -a^_j * ub_j
8662 * to the rhs.
8663 *
8664 * (vlb or vub):
8665 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
8666 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
8667 * move the constant terms
8668 * -a~_j * dl_j == -a^_j * dl_j, or
8669 * a~_j * du_j == -a^_j * du_j
8670 * to the rhs, and update the VB variable coefficients:
8671 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
8672 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
8673 */
8674
8675 ntmpcoefs = 0;
8676 assert(mksetnnz <= nvars);
8677 for( i = intstart; i < mksetnnz; ++i )
8678 {
8679 SCIP_VAR* var;
8680 SCIP_Real solval;
8681 SCIP_Real QUAD(coef);
8682
8683 var = vars[mksetinds[i]];
8684
8685 /* get the soltion value of the continuous variable */
8686 solval = SCIPgetSolVal(scip, sol, var);
8687
8688 /* now compute the solution value in the transform space considering complementation */
8689 if( boundtype[i] == -1 )
8690 {
8691 /* variable was complemented with global (simple) bound */
8692 if( varsign[i] == -1 )
8693 solval = SCIPvarGetUbGlobal(var) - solval;
8694 else
8695 solval = solval - SCIPvarGetLbGlobal(var);
8696 }
8697 else
8698 {
8699 assert(boundtype[i] == -2);
8700
8701 /* variable was complemented with local (simple) bound */
8702 if( varsign[i] == -1 )
8703 solval = SCIPvarGetUbLocal(var) - solval;
8704 else
8705 solval = solval - SCIPvarGetLbLocal(var);
8706 }
8707
8708 tmpvalues[ntmpcoefs] = solval;
8709 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
8710 tmpcoefs[ntmpcoefs] = varsign[i] * QUAD_TO_DBL(coef);
8711 ++ntmpcoefs;
8712 }
8713
8714 assert(ntmpcoefs == mksetnnz - intstart);
8715
8716 contactivity = 0.0;
8717 contsqrnorm = 0.0;
8718 for( i = 0; i < intstart; ++i )
8719 {
8720 SCIP_Real solval;
8721 SCIP_Real QUAD(mksetcoef);
8722
8723 QUAD_ARRAY_LOAD(mksetcoef, mksetcoefs, mksetinds[i]);
8724
8725 if( varsign[i] * QUAD_TO_DBL(mksetcoef) >= 0.0 )
8726 continue;
8727
8728 /* get the soltion value of the continuous variable */
8729 solval = SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
8730
8731 /* now compute the solution value in the transform space considering complementation */
8732 switch( boundtype[i] )
8733 {
8734 case -1:
8735 /* variable was complemented with global (simple) bound */
8736 if( varsign[i] == -1 )
8737 solval = SCIPvarGetUbGlobal(vars[mksetinds[i]]) - solval;
8738 else
8739 solval = solval - SCIPvarGetLbGlobal(vars[mksetinds[i]]);
8740 break;
8741 case -2:
8742 /* variable was complemented with local (simple) bound */
8743 if( varsign[i] == -1 )
8744 solval = SCIPvarGetUbLocal(vars[mksetinds[i]]) - solval;
8745 else
8746 solval = solval - SCIPvarGetLbLocal(vars[mksetinds[i]]);
8747 break;
8748 default:
8749 /* variable was complemented with a variable bound */
8750 if( varsign[i] == -1 )
8751 {
8752 SCIP_Real coef;
8753 SCIP_Real constant;
8754 SCIP_Real vbdsolval;
8755
8756 coef = SCIPvarGetVubCoefs(vars[mksetinds[i]])[boundtype[i]];
8757 constant = SCIPvarGetVubConstants(vars[mksetinds[i]])[boundtype[i]];
8758 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVubVars(vars[mksetinds[i]])[boundtype[i]]);
8759
8760 solval = (coef * vbdsolval + constant) - solval;
8761 }
8762 else
8763 {
8764 SCIP_Real coef;
8765 SCIP_Real constant;
8766 SCIP_Real vbdsolval;
8767
8768 coef = SCIPvarGetVlbCoefs(vars[mksetinds[i]])[boundtype[i]];
8769 constant = SCIPvarGetVlbConstants(vars[mksetinds[i]])[boundtype[i]];
8770 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVlbVars(vars[mksetinds[i]])[boundtype[i]]);
8771
8772 solval = solval - (coef * vbdsolval + constant);
8773 }
8774 }
8775
8776 contactivity += solval * (QUAD_TO_DBL(mksetcoef) * varsign[i]);
8777 contsqrnorm += QUAD_TO_DBL(mksetcoef) * QUAD_TO_DBL(mksetcoef);
8778 }
8779
8780 {
8781 SCIP_ROW** rows;
8782
8783 rows = SCIPgetLPRows(scip);
8784 assert(ntmpcoefs <= nvars);
8785 for( i = 0; i < aggrrow->nrows; ++i )
8786 {
8787 SCIP_ROW* row;
8788 SCIP_Real slackval;
8789
8790 row = rows[aggrrow->rowsinds[i]];
8791
8792 if( (aggrrow->rowweights[i] * aggrrow->slacksign[i]) >= 0.0 && !row->integral )
8793 continue;
8794
8795 /* compute solution value of slack variable */
8796 slackval = SCIPgetRowSolActivity(scip, row, sol);
8797
8798 if( aggrrow->slacksign[i] == +1 )
8799 {
8800 /* right hand side */
8801 assert(!SCIPisInfinity(scip, row->rhs));
8802
8803 slackval = row->rhs - slackval;
8804 }
8805 else
8806 {
8807 /* left hand side */
8808 assert(aggrrow->slacksign[i] == -1);
8809 assert(!SCIPisInfinity(scip, -row->lhs));
8810
8811 slackval = slackval - row->lhs;
8812 }
8813
8814 if( row->integral )
8815 {
8816 /* if row is integral add variable to tmp arrays */
8817 tmpvalues[ntmpcoefs] = slackval;
8818 tmpcoefs[ntmpcoefs] = aggrrow->rowweights[i] * aggrrow->slacksign[i];
8819 ++ntmpcoefs;
8820 }
8821 else
8822 {
8823 SCIP_Real slackcoeff = (aggrrow->rowweights[i] * aggrrow->slacksign[i]);
8824
8825 /* otherwise add it to continuous activity */
8826 contactivity += slackval * slackcoeff;
8827 contsqrnorm += SQR(slackcoeff);
8828 }
8829 }
8830 }
8831
8832 /* try all candidates for delta and remember best */
8833 bestdelta = SCIP_INVALID;
8834 bestefficacy = -SCIPinfinity(scip);
8835
8836 for( i = 0; i < maxtestdelta; ++i )
8837 {
8838 int j;
8839 SCIP_Real efficacy;
8840
8841 /* check if we have seen this value of delta before */
8842 SCIP_Bool deltaseenbefore = FALSE;
8843 for( j = 0; j < i; ++j )
8844 {
8845 if( SCIPisEQ(scip, deltacands[i], deltacands[j]) )
8846 {
8847 deltaseenbefore = TRUE;
8848 break;
8849 }
8850 }
8851
8852 /* skip this delta value and allow one more delta value if available */
8853 if( deltaseenbefore )
8854 {
8855 maxtestdelta = MIN(maxtestdelta + 1, ndeltacands);
8856 continue;
8857 }
8858
8859 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, deltacands[i], ntmpcoefs, minfrac, maxfrac);
8860
8861 if( efficacy > bestefficacy )
8862 {
8863 bestefficacy = efficacy;
8864 bestdelta = deltacands[i];
8865 }
8866 }
8867
8868 /* no delta was found that yielded any cut */
8869 if( bestdelta == SCIP_INVALID ) /*lint !e777*/
8870 goto TERMINATE;
8871
8872 /* try bestdelta divided by 2, 4 and 8 */
8873 {
8874 SCIP_Real basedelta = bestdelta;
8875 for( i = 2; i <= 8 ; i *= 2 )
8876 {
8877 SCIP_Real efficacy;
8878 SCIP_Real delta;
8879
8880 delta = basedelta / i;
8881
8882 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, delta, ntmpcoefs, minfrac, maxfrac);
8883
8884 if( efficacy > bestefficacy )
8885 {
8886 bestefficacy = efficacy;
8887 bestdelta = delta;
8888 }
8889 }
8890 }
8891
8892 /* try to improve efficacy by switching complementation of integral variables that are not at their bounds
8893 * in order of non-increasing bound distance
8894 */
8895 for( i = 0; i < nbounddist; ++i )
8896 {
8897 int k;
8898 SCIP_Real newefficacy;
8899 SCIP_Real QUAD(newrhs);
8900 SCIP_Real QUAD(quadprod);
8901 SCIP_Real bestlb;
8902 SCIP_Real bestub;
8903 SCIP_Real oldsolval;
8904 int bestlbtype;
8905 int bestubtype;
8906
8907 k = bounddistpos[i];
8908
8909 SCIP_CALL( findBestLb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestlb, &bestlbtype) );
8910
8911 if( SCIPisInfinity(scip, -bestlb) )
8912 continue;
8913
8914 SCIP_CALL( findBestUb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestub, &bestubtype) );
8915
8916 if( SCIPisInfinity(scip, bestub) )
8917 continue;
8918
8919 /* switch the complementation of this variable */
8920#ifndef NDEBUG
8921 {
8922 SCIP_Real QUAD(coef);
8923 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[k]);
8924 assert(SCIPisEQ(scip, tmpcoefs[k - intstart], varsign[k] * QUAD_TO_DBL(coef)));
8925 }
8926#endif
8927
8928 /* compute this: newrhs = mksetrhs + tmpcoefs[k - intstart] * (bestlb - bestub); */
8929 SCIPquadprecProdDD(quadprod, tmpcoefs[k - intstart], bestlb - bestub);
8930 SCIPquadprecSumQQ(newrhs, mksetrhs, quadprod);
8931 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
8932
8933 oldsolval = tmpvalues[k - intstart];
8934 tmpvalues[k - intstart] = varsign[k] == +1 ? bestub - SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) : SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) - bestlb;
8935
8936 /* compute new violation */
8937 newefficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(newrhs), contactivity, contsqrnorm, bestdelta, ntmpcoefs, minfrac, maxfrac);
8938
8939 /* check if violation was increased */
8940 if( newefficacy > bestefficacy )
8941 {
8942 /* keep change of complementation */
8943 bestefficacy = newefficacy;
8944 QUAD_ASSIGN_Q(mksetrhs, newrhs);
8945
8946 if( varsign[k] == +1 )
8947 {
8948 /* switch to upper bound */
8949 assert(bestubtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
8950 boundtype[k] = bestubtype;
8951 varsign[k] = -1;
8952 }
8953 else
8954 {
8955 /* switch to lower bound */
8956 assert(bestlbtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
8957 boundtype[k] = bestlbtype;
8958 varsign[k] = +1;
8959 }
8960
8961 localbdsused = localbdsused || (boundtype[k] == -2);
8962 }
8963 else
8964 {
8965 /* undo the change of the complementation */
8966 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
8967 tmpvalues[k - intstart] = oldsolval;
8968 }
8969 } /*lint !e438*/
8970
8971 if( bestefficacy > 0.0 )
8972 {
8973 SCIP_Real mirefficacy;
8974 SCIP_Real QUAD(downrhs);
8975 SCIP_Real QUAD(f0);
8976 SCIP_Real scale;
8977
8978 scale = 1.0 / bestdelta;
8979 SCIPquadprecProdQD(mksetrhs, mksetrhs, scale);
8980 SCIPquadprecEpsFloorQ(downrhs, mksetrhs, SCIPepsilon(scip)); /*lint !e666*/
8981 SCIPquadprecSumQQ(f0, mksetrhs, -downrhs);
8982 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
8983
8984 /* renormalize f0 value */
8985 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
8986
8987 /* scale entries by the chosen scale factor */
8988 for( i = 0; i < mksetnnz; ++i )
8989 {
8990 SCIP_Real QUAD(coef);
8991
8992 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
8993 SCIPquadprecProdQD(coef, coef, scale);
8994 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], coef);
8995 }
8996 SCIPdebugMsg(scip, "applied best scale (=%.13g):\n", scale);
8997 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
8998
8999 QUAD_ASSIGN_Q(mksetrhs, downrhs);
9000
9001 QUAD_ASSIGN_Q(data->cutrhs, mksetrhs);
9002
9003 SCIP_CALL( cutsRoundMIR(scip, data, varsign, boundtype, QUAD(f0)) );
9004
9005 SCIPdebugMsg(scip, "rounded MIR cut:\n");
9006 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
9007
9008 /* substitute aggregated slack variables:
9009 *
9010 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
9011 * variable only appears in its own row:
9012 * a'_r = scale * weight[r] * slacksign[r].
9013 *
9014 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
9015 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
9016 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
9017 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
9018 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
9019 *
9020 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
9021 */
9022 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
9023 aggrrow->nrows, scale, mksetcoefs, QUAD(&data->cutrhs), mksetinds, &data->ncutinds, QUAD(f0)) );
9024
9025 SCIPdebugMsg(scip, "substituted slacks in MIR cut:\n");
9026 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
9027
9028#ifndef NDEBUG
9029 {
9030 SCIP_Real efficacy = -QUAD_TO_DBL(data->cutrhs);
9031 for( i = 0; i < data->ncutinds; ++i )
9032 {
9033 SCIP_Real QUAD(coef);
9034 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
9035 efficacy += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
9036 }
9037
9038 if( !EPSZ(SCIPrelDiff(efficacy, bestefficacy), 1e-4) )
9039 {
9040 SCIPdebugMsg(scip, "efficacy of cmir cut is different than expected efficacy: %f != %f\n", efficacy, bestefficacy);
9041 }
9042 }
9043#endif
9044
9045 *cutislocal = *cutislocal || localbdsused;
9046
9047 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
9048 * prevent numerical rounding errors
9049 */
9050 if( postprocess )
9051 {
9052 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, mksetinds, mksetcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
9053 }
9054 else
9055 {
9056 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, mksetcoefs, QUAD(&data->cutrhs), mksetinds, &data->ncutinds);
9057 }
9058
9059 SCIPdebugMsg(scip, "post-processed cut (success = %s):\n", *success ? "TRUE" : "FALSE");
9060 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
9061
9062 if( *success )
9063 {
9064 mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, mksetcoefs, QUAD_TO_DBL(data->cutrhs), mksetinds, data->ncutinds);
9065
9066 if( SCIPisEfficacious(scip, mirefficacy) && SCIPisGT(scip, mirefficacy, *cutefficacy) )
9067 {
9068 BMScopyMemoryArray(cutinds, mksetinds, data->ncutinds);
9069 for( i = 0; i < data->ncutinds; ++i )
9070 {
9071 SCIP_Real QUAD(coef);
9072 int j = cutinds[i];
9073
9074 QUAD_ARRAY_LOAD(coef, mksetcoefs, j);
9075
9076 cutcoefs[i] = QUAD_TO_DBL(coef);
9077 QUAD_ASSIGN(coef, 0.0);
9078 QUAD_ARRAY_STORE(mksetcoefs, j, coef);
9079 }
9080 *cutnnz = data->ncutinds;
9081 *cutrhs = QUAD_TO_DBL(data->cutrhs);
9082 *cutefficacy = mirefficacy;
9083 if( cutrank != NULL )
9084 *cutrank = aggrrow->rank + 1;
9085 *cutislocal = *cutislocal || localbdsused;
9086 }
9087 else
9088 *success = FALSE;
9089 }
9090 }
9091
9092 TERMINATE:
9093 /* if we aborted early we need to clean the mksetcoefs */
9094 if( !(*success) )
9095 {
9096 SCIP_Real QUAD(tmp);
9097 QUAD_ASSIGN(tmp, 0.0);
9098
9099 for( i = 0; i < data->ncutinds; ++i )
9100 {
9101 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], tmp);
9102 }
9103 }
9104
9105#ifndef NDEBUG
9106 for( i = 0; i < QUAD_ARRAY_SIZE(nvars); ++i )
9107 {
9108 if(mksetcoefs[i] != 0.0)
9109 {
9110 SCIPdebugMsg(scip, "mksetcoefs have not been reset\n");
9111 SCIPABORT();
9112 }
9113 }
9114#endif
9115
9116 if( data->cutinds != NULL )
9118
9119 if( data->cutcoefs != NULL )
9121
9122 for( int s = NSECTIONS - 1; s >= 0; --s )
9123 {
9125 }
9126
9127 SCIPfreeBuffer(scip, &data);
9128 /* free temporary memory */
9129 SCIPfreeBufferArray(scip, &bounddistpos);
9130 SCIPfreeBufferArray(scip, &bounddist);
9131 SCIPfreeBufferArray(scip, &deltacands);
9132 SCIPfreeBufferArray(scip, &tmpvalues);
9133 SCIPfreeBufferArray(scip, &tmpcoefs);
9134 SCIPfreeBufferArray(scip, &boundtype);
9135 SCIPfreeBufferArray(scip, &varsign);
9136
9137 return SCIP_OKAY;
9138}
9139
9140/* =========================================== flow cover =========================================== */
9141
9142#define NO_EXACT_KNAPSACK
9143
9144#ifndef NO_EXACT_KNAPSACK
9145#define MAXDNOM 1000LL
9146#define MINDELTA 1e-03
9147#define MAXDELTA 1e-09
9148#define MAXSCALE 1000.0
9149#define MAXDYNPROGSPACE 1000000
9150#endif
9151
9152#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for snf relaxation */
9153#define MAXBOUND 1e+10 /**< maximal value of normal bounds used for snf relaxation */
9154
9155/** structure that contains all data required to perform the sequence independent lifting
9156 */
9157typedef
9158struct LiftingData
9159{
9160 SCIP_Real* M; /**< \f$ M_0 := 0.0 \f$ and \f$ M_i := M_i-1 + m_i \f$ */
9161 SCIP_Real* m; /**< non-increasing array of variable upper bound coefficients
9162 * for all variables in \f$ C^{++} \f$ and \f$ L^- \f$,
9163 * where \f$ C = C^+ \cup C^- \f$ is the flowcover and
9164 * \f$ C^{++} := \{ j \in C^+ \mid u_j > \lambda \} \f$
9165 * \f$ L^- := \{ j \in (N^- \setminus C^-) \mid u_j > \lambda \} \f$
9166 */
9167 int r; /**< size of array m */
9168 int t; /**< index of smallest value in m that comes from a variable in \f$ C^{++} \f$ */
9169 SCIP_Real d1; /**< right hand side of single-node-flow set plus the sum of all \f$ u_j \f$ for \f$ j \in C^- \f$ */
9170 SCIP_Real d2; /**< right hand side of single-node-flow set plus the sum of all \f$ u_j \f$ for \f$ j \in N^- \f$ */
9171 SCIP_Real lambda; /**< excess of the flowcover */
9172 SCIP_Real mp; /**< smallest variable bound coefficient of variable in \f$ C^{++} (min_{j \in C++} u_j) \f$ */
9173 SCIP_Real ml; /**< \f$ ml := min(\lambda, \sum_{j \in C^+ \setminus C^{++}} u_j) \f$ */
9175
9176/** structure that contains all the data that defines the single-node-flow relaxation of an aggregation row */
9177typedef
9178struct SNF_Relaxation
9179{
9180 int* transvarcoefs; /**< coefficients of all vars in relaxed set */
9181 SCIP_Real* transbinvarsolvals; /**< sol val of bin var in vub of all vars in relaxed set */
9182 SCIP_Real* transcontvarsolvals;/**< sol val of all real vars in relaxed set */
9183 SCIP_Real* transvarvubcoefs; /**< coefficient in vub of all vars in relaxed set */
9184 int ntransvars; /**< number of vars in relaxed set */
9185 SCIP_Real transrhs; /**< rhs in relaxed set */
9186 int* origbinvars; /**< associated original binary var for all vars in relaxed set */
9187 int* origcontvars; /**< associated original continuous var for all vars in relaxed set */
9188 SCIP_Real* aggrcoefsbin; /**< aggregation coefficient of the original binary var used to define the
9189 * continuous variable in the relaxed set */
9190 SCIP_Real* aggrcoefscont; /**< aggregation coefficient of the original continuous var used to define the
9191 * continuous variable in the relaxed set */
9192 SCIP_Real* aggrconstants; /**< aggregation constant used to define the continuous variable in the relaxed set */
9194
9195/** get solution value and index of variable lower bound (with binary variable) which is closest to the current LP
9196 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
9197 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
9198 * given variable
9199 */
9200static
9202 SCIP* scip, /**< SCIP data structure */
9203 SCIP_VAR* var, /**< given active problem variable */
9204 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
9205 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
9206 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
9207 * was not used (0) or was not used but is contained in the row (-1) */
9208 SCIP_Real bestsub, /**< closest simple upper bound of given variable */
9209 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
9210 SCIP_Real* closestvlb, /**< pointer to store the LP sol value of the closest variable lower bound */
9211 int* closestvlbidx /**< pointer to store the index of the closest vlb; -1 if no vlb was found */
9212 )
9213{
9214 int nvlbs;
9215 int nbinvars;
9216
9217 assert(scip != NULL);
9218 assert(var != NULL);
9219 assert(bestsub == SCIPvarGetUbGlobal(var) || bestsub == SCIPvarGetUbLocal(var)); /*lint !e777*/
9220 assert(!SCIPisInfinity(scip, bestsub));
9221 assert(!EPSZ(rowcoef, QUAD_EPSILON));
9222 assert(rowcoefs != NULL);
9223 assert(binvarused != NULL);
9224 assert(closestvlb != NULL);
9225 assert(closestvlbidx != NULL);
9226
9227 nvlbs = SCIPvarGetNVlbs(var);
9228 nbinvars = SCIPgetNBinVars(scip);
9229
9230 *closestvlbidx = -1;
9231 *closestvlb = -SCIPinfinity(scip);
9232 if( nvlbs > 0 )
9233 {
9234 SCIP_VAR** vlbvars;
9235 SCIP_Real* vlbcoefs;
9236 SCIP_Real* vlbconsts;
9237 int i;
9238
9239 vlbvars = SCIPvarGetVlbVars(var);
9240 vlbcoefs = SCIPvarGetVlbCoefs(var);
9241 vlbconsts = SCIPvarGetVlbConstants(var);
9242
9243 for( i = 0; i < nvlbs; i++ )
9244 {
9245 SCIP_Real rowcoefbinvar;
9246 SCIP_Real val1;
9247 SCIP_Real val2;
9248 SCIP_Real vlbsol;
9249 SCIP_Real rowcoefsign;
9250 int probidxbinvar;
9251
9252 if( bestsub > vlbconsts[i] )
9253 continue;
9254
9255 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
9256 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
9257 */
9258 if( REALABS(vlbcoefs[i]) > MAXABSVBCOEF )
9259 continue;
9260
9261 /* use only variable lower bounds l~_i * x_i + d_i with x_i binary which are active */
9262 probidxbinvar = SCIPvarGetProbindex(vlbvars[i]);
9263
9264 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
9265 * ensures that the problem index is between 0 and nbinvars - 1
9266 */
9267 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
9268 continue;
9269
9270 assert(SCIPvarIsBinary(vlbvars[i]));
9271
9272 /* check if current variable lower bound l~_i * x_i + d_i imposed on y_j meets the following criteria:
9273 * (let a_j = coefficient of y_j in current row,
9274 * u_j = closest simple upper bound imposed on y_j,
9275 * c_i = coefficient of x_i in current row)
9276 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k yet
9277 * if a_j > 0:
9278 * 1. u_j <= d_i
9279 * 2. a_j ( u_j - d_i ) + c_i <= 0
9280 * 3. a_j l~_i + c_i <= 0
9281 * if a_j < 0:
9282 * 1. u_j <= d_i
9283 * 2. a_j ( u_j - d_i ) + c_i >= 0
9284 * 3. a_j l~_i + c_i >= 0
9285 */
9286
9287 /* has already been used in the SNF relaxation */
9288 if( binvarused[probidxbinvar] == 1 )
9289 continue;
9290
9291 /* get the row coefficient */
9292 {
9293 SCIP_Real QUAD(tmp);
9294 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
9295 rowcoefbinvar = QUAD_TO_DBL(tmp);
9296 }
9297 rowcoefsign = COPYSIGN(1.0, rowcoef);
9298
9299 val2 = rowcoefsign * ((rowcoef * vlbcoefs[i]) + rowcoefbinvar);
9300
9301 /* variable lower bound does not meet criteria */
9302 if( val2 > 0.0 || SCIPisInfinity(scip, -val2) )
9303 continue;
9304
9305 val1 = rowcoefsign * ((rowcoef * (bestsub - vlbconsts[i])) + rowcoefbinvar);
9306
9307 /* variable lower bound does not meet criteria */
9308 if( val1 > 0.0 )
9309 continue;
9310
9311 vlbsol = vlbcoefs[i] * SCIPgetSolVal(scip, sol, vlbvars[i]) + vlbconsts[i];
9312 if( vlbsol > *closestvlb )
9313 {
9314 *closestvlb = vlbsol;
9315 *closestvlbidx = i;
9316 }
9317 assert(*closestvlbidx >= 0);
9318 }
9319 }
9320
9321 return SCIP_OKAY;
9322}
9323
9324/** get LP solution value and index of variable upper bound (with binary variable) which is closest to the current LP
9325 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
9326 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
9327 * given variable
9328 */
9329static
9331 SCIP* scip, /**< SCIP data structure */
9332 SCIP_VAR* var, /**< given active problem variable */
9333 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
9334 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
9335 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
9336 * was not used (0) or was not used but is contained in the row (-1)
9337 */
9338 SCIP_Real bestslb, /**< closest simple lower bound of given variable */
9339 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
9340 SCIP_Real* closestvub, /**< pointer to store the LP sol value of the closest variable upper bound */
9341 int* closestvubidx /**< pointer to store the index of the closest vub; -1 if no vub was found */
9342 )
9343{
9344 int nvubs;
9345 int nbinvars;
9346
9347 assert(scip != NULL);
9348 assert(var != NULL);
9349 assert(bestslb == SCIPvarGetLbGlobal(var) || bestslb == SCIPvarGetLbLocal(var)); /*lint !e777*/
9350 assert(!SCIPisInfinity(scip, - bestslb));
9351 assert(!EPSZ(rowcoef, QUAD_EPSILON));
9352 assert(rowcoefs != NULL);
9353 assert(binvarused != NULL);
9354 assert(closestvub != NULL);
9355 assert(closestvubidx != NULL);
9356
9357 nvubs = SCIPvarGetNVubs(var);
9358 nbinvars = SCIPgetNBinVars(scip);
9359
9360 *closestvubidx = -1;
9361 *closestvub = SCIPinfinity(scip);
9362 if( nvubs > 0 )
9363 {
9364 SCIP_VAR** vubvars;
9365 SCIP_Real* vubcoefs;
9366 SCIP_Real* vubconsts;
9367 int i;
9368
9369 vubvars = SCIPvarGetVubVars(var);
9370 vubcoefs = SCIPvarGetVubCoefs(var);
9371 vubconsts = SCIPvarGetVubConstants(var);
9372
9373 for( i = 0; i < nvubs; i++ )
9374 {
9375 SCIP_Real rowcoefbinvar;
9376 SCIP_Real val1;
9377 SCIP_Real val2;
9378 SCIP_Real vubsol;
9379 SCIP_Real rowcoefsign;
9380 int probidxbinvar;
9381
9382 if( bestslb < vubconsts[i] )
9383 continue;
9384
9385 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
9386 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
9387 */
9388 if( REALABS(vubcoefs[i]) > MAXABSVBCOEF )
9389 continue;
9390
9391 /* use only variable upper bound u~_i * x_i + d_i with x_i binary and which are active */
9392 probidxbinvar = SCIPvarGetProbindex(vubvars[i]);
9393
9394 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
9395 * ensures that the problem index is between 0 and nbinvars - 1
9396 */
9397 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
9398 continue;
9399
9400 assert(SCIPvarIsBinary(vubvars[i]));
9401
9402 /* checks if current variable upper bound u~_i * x_i + d_i meets the following criteria
9403 * (let a_j = coefficient of y_j in current row,
9404 * l_j = closest simple lower bound imposed on y_j,
9405 * c_i = coefficient of x_i in current row)
9406 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k
9407 * if a > 0:
9408 * 1. l_j >= d_i
9409 * 2. a_j ( l_i - d_i ) + c_i >= 0
9410 * 3. a_j u~_i + c_i >= 0
9411 * if a < 0:
9412 * 1. l_j >= d_i
9413 * 2. a_j ( l_j - d_i ) + c_i <= 0
9414 * 3. a_j u~_i + c_i <= 0
9415 */
9416
9417 /* has already been used in the SNF relaxation */
9418 if( binvarused[probidxbinvar] == 1 )
9419 continue;
9420
9421 /* get the row coefficient */
9422 {
9423 SCIP_Real QUAD(tmp);
9424 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
9425 rowcoefbinvar = QUAD_TO_DBL(tmp);
9426 }
9427 rowcoefsign = COPYSIGN(1.0, rowcoef);
9428
9429 val2 = rowcoefsign * ((rowcoef * vubcoefs[i]) + rowcoefbinvar);
9430
9431 /* variable upper bound does not meet criteria */
9432 if( val2 < 0.0 || SCIPisInfinity(scip, val2) )
9433 continue;
9434
9435 val1 = rowcoefsign * ((rowcoef * (bestslb - vubconsts[i])) + rowcoefbinvar);
9436
9437 /* variable upper bound does not meet criteria */
9438 if( val1 < 0.0 )
9439 continue;
9440
9441 vubsol = vubcoefs[i] * SCIPgetSolVal(scip, sol, vubvars[i]) + vubconsts[i];
9442 if( vubsol < *closestvub )
9443 {
9444 *closestvub = vubsol;
9445 *closestvubidx = i;
9446 }
9447 assert(*closestvubidx >= 0);
9448 }
9449 }
9450
9451 return SCIP_OKAY;
9452}
9453
9454/** determines the bounds to use for constructing the single-node-flow relaxation of a variable in
9455 * the given row.
9456 */
9457static
9459 SCIP* scip, /**< SCIP data structure */
9460 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
9461 SCIP_VAR** vars, /**< array of problem variables */
9462 SCIP_Real* rowcoefs, /**< (dense) array of variable coefficients in the row */
9463 int* rowinds, /**< array with positions of non-zero values in the rowcoefs array */
9464 int varposinrow, /**< position of variable in the rowinds array for which the bounds should be determined */
9465 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
9466 * was not used (0) or was not used but is contained in the row (-1)
9467 */
9468 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
9469 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
9470 SCIP_Real* bestlb, /**< pointer to store best lower bound for transformation */
9471 SCIP_Real* bestub, /**< pointer to store best upper bound for transformation */
9472 SCIP_Real* bestslb, /**< pointer to store best simple lower bound for transformation */
9473 SCIP_Real* bestsub, /**< pointer to store best simple upper bound for transformation */
9474 int* bestlbtype, /**< pointer to store type of best lower bound (-2: local bound, -1: global bound, >= 0 variable bound index) */
9475 int* bestubtype, /**< pointer to store type of best upper bound (-2: local bound, -1: global bound, >= 0 variable bound index) */
9476 int* bestslbtype, /**< pointer to store type of best simple lower bound */
9477 int* bestsubtype, /**< pointer to store type of best simple upper bound */
9478 SCIP_BOUNDTYPE* selectedbounds, /**< pointer to store the preferred bound for the transformation */
9479 SCIP_Bool* freevariable /**< pointer to store if variable is a free variable */
9480 )
9481{
9482 SCIP_VAR* var;
9483
9484 SCIP_Real rowcoef;
9485 SCIP_Real solval;
9486
9487 int probidx;
9488
9489 bestlb[varposinrow] = -SCIPinfinity(scip);
9490 bestub[varposinrow] = SCIPinfinity(scip);
9491 bestlbtype[varposinrow] = -3;
9492 bestubtype[varposinrow] = -3;
9493
9494 probidx = rowinds[varposinrow];
9495 var = vars[probidx];
9496 {
9497 SCIP_Real QUAD(tmp);
9498 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidx);
9499 rowcoef = QUAD_TO_DBL(tmp);
9500 }
9501
9502 assert(!EPSZ(rowcoef, QUAD_EPSILON));
9503
9504 /* get closest simple lower bound and closest simple upper bound */
9505 SCIP_CALL( findBestLb(scip, var, sol, 0, allowlocal, &bestslb[varposinrow], &bestslbtype[varposinrow]) );
9506 SCIP_CALL( findBestUb(scip, var, sol, 0, allowlocal, &bestsub[varposinrow], &bestsubtype[varposinrow]) );
9507
9508 /* do not use too large bounds */
9509 if( bestslb[varposinrow] <= -MAXBOUND )
9510 bestslb[varposinrow] = -SCIPinfinity(scip);
9511
9512 if( bestsub[varposinrow] >= MAXBOUND )
9513 bestsub[varposinrow] = SCIPinfinity(scip);
9514
9515 solval = SCIPgetSolVal(scip, sol, var);
9516
9517 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g(%d),%g(%d)]>:\n", varposinrow, rowcoef, SCIPvarGetName(var), probidx,
9518 solval, bestslb[varposinrow], bestslbtype[varposinrow], bestsub[varposinrow], bestsubtype[varposinrow]);
9519
9520 /* mixed integer set cannot be relaxed to 0-1 single node flow set because both simple bounds are -infinity
9521 * and infinity, respectively
9522 */
9523 if( SCIPisInfinity(scip, -bestslb[varposinrow]) && SCIPisInfinity(scip, bestsub[varposinrow]) )
9524 {
9525 *freevariable = TRUE;
9526 return SCIP_OKAY;
9527 }
9528
9529 /* get closest lower bound that can be used to define the real variable y'_j in the 0-1 single node flow
9530 * relaxation
9531 */
9532 if( !SCIPisInfinity(scip, bestsub[varposinrow]) )
9533 {
9534 bestlb[varposinrow] = bestslb[varposinrow];
9535 bestlbtype[varposinrow] = bestslbtype[varposinrow];
9536
9538 {
9539 SCIP_Real bestvlb;
9540 int bestvlbidx;
9541
9542 SCIP_CALL( getClosestVlb(scip, var, sol, rowcoefs, binvarused, bestsub[varposinrow], rowcoef, &bestvlb, &bestvlbidx) );
9543 if( SCIPisGT(scip, bestvlb, bestlb[varposinrow]) )
9544 {
9545 bestlb[varposinrow] = bestvlb;
9546 bestlbtype[varposinrow] = bestvlbidx;
9547 }
9548 }
9549 }
9550
9551 /* get closest upper bound that can be used to define the real variable y'_j in the 0-1 single node flow
9552 * relaxation
9553 */
9554 if( !SCIPisInfinity(scip, -bestslb[varposinrow]) )
9555 {
9556 bestub[varposinrow] = bestsub[varposinrow];
9557 bestubtype[varposinrow] = bestsubtype[varposinrow];
9558
9560 {
9561 SCIP_Real bestvub;
9562 int bestvubidx;
9563
9564 SCIP_CALL( getClosestVub(scip, var, sol, rowcoefs, binvarused, bestslb[varposinrow], rowcoef, &bestvub, &bestvubidx) );
9565 if( SCIPisLT(scip, bestvub, bestub[varposinrow]) )
9566 {
9567 bestub[varposinrow] = bestvub;
9568 bestubtype[varposinrow] = bestvubidx;
9569 }
9570 }
9571 }
9572 SCIPdebugMsg(scip, " bestlb=%g(%d), bestub=%g(%d)\n", bestlb[varposinrow], bestlbtype[varposinrow], bestub[varposinrow], bestubtype[varposinrow]);
9573
9574 /* mixed integer set cannot be relaxed to 0-1 single node flow set because there are no suitable bounds
9575 * to define the transformed variable y'_j
9576 */
9577 if( SCIPisInfinity(scip, -bestlb[varposinrow]) && SCIPisInfinity(scip, bestub[varposinrow]) )
9578 {
9579 *freevariable = TRUE;
9580 return SCIP_OKAY;
9581 }
9582
9583 *freevariable = FALSE;
9584
9585 /* select best upper bound if it is closer to the LP value of y_j and best lower bound otherwise and use this bound
9586 * to define the real variable y'_j with 0 <= y'_j <= u'_j x_j in the 0-1 single node flow relaxation;
9587 * prefer variable bounds
9588 */
9589 if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) && bestlbtype[varposinrow] >= 0 )
9590 {
9591 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
9592 }
9593 else if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow])
9594 && bestubtype[varposinrow] >= 0 )
9595 {
9596 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
9597 }
9598 else if( SCIPisLE(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) )
9599 {
9600 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
9601 }
9602 else
9603 {
9604 assert(SCIPisGT(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]));
9605 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
9606 }
9607
9608 if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_LOWER && bestlbtype[varposinrow] >= 0 )
9609 {
9610 int vlbvarprobidx;
9611 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
9612
9613 /* mark binary variable of vlb so that it is not used for other continuous variables
9614 * by setting it's position in the aggrrow to a negative value
9615 */
9616 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[varposinrow]]);
9617 binvarused[vlbvarprobidx] = 1;
9618 }
9619 else if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_UPPER && bestubtype[varposinrow] >= 0 )
9620 {
9621 int vubvarprobidx;
9622 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
9623
9624 /* mark binary variable of vub so that it is not used for other continuous variables
9625 * by setting it's position in the aggrrow to a negative value
9626 */
9627 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[varposinrow]]);
9628 binvarused[vubvarprobidx] = 1;
9629 }
9630
9631 return SCIP_OKAY; /*lint !e438*/
9632}
9633
9634/** construct a 0-1 single node flow relaxation (with some additional simple constraints) of a mixed integer set
9635 * corresponding to the given aggrrow a * x <= rhs
9636 */
9637static
9639 SCIP* scip, /**< SCIP data structure */
9640 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
9641 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
9642 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
9643 SCIP_Real* rowcoefs, /**< array of coefficients of row */
9644 QUAD(SCIP_Real rowrhs), /**< pointer to right hand side of row */
9645 int* rowinds, /**< array of variables problem indices for non-zero coefficients in row */
9646 int nnz, /**< number of non-zeros in row */
9647 SNF_RELAXATION* snf, /**< stores the sign of the transformed variable in summation */
9648 SCIP_Bool* success, /**< stores whether the transformation was valid */
9649 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
9650 )
9651{
9652 SCIP_VAR** vars;
9653 int i;
9654 int nnonbinvarsrow;
9655 int8_t* binvarused;
9656 int nbinvars;
9657 SCIP_Real QUAD(transrhs);
9658
9659 /* arrays to store the selected bound for each non-binary variable in the row */
9660 SCIP_Real* bestlb;
9661 SCIP_Real* bestub;
9662 SCIP_Real* bestslb;
9663 SCIP_Real* bestsub;
9664 int* bestlbtype;
9665 int* bestubtype;
9666 int* bestslbtype;
9667 int* bestsubtype;
9668 SCIP_BOUNDTYPE* selectedbounds;
9669
9670 *success = FALSE;
9671
9672 SCIPdebugMsg(scip, "--------------------- construction of SNF relaxation ------------------------------------\n");
9673
9674 nbinvars = SCIPgetNBinVars(scip);
9676
9677 SCIP_CALL( SCIPallocBufferArray(scip, &bestlb, nnz) );
9678 SCIP_CALL( SCIPallocBufferArray(scip, &bestub, nnz) );
9679 SCIP_CALL( SCIPallocBufferArray(scip, &bestslb, nnz) );
9680 SCIP_CALL( SCIPallocBufferArray(scip, &bestsub, nnz) );
9681 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtype, nnz) );
9682 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtype, nnz) );
9683 SCIP_CALL( SCIPallocBufferArray(scip, &bestslbtype, nnz) );
9684 SCIP_CALL( SCIPallocBufferArray(scip, &bestsubtype, nnz) );
9685 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, nnz) );
9686
9687 /* sort descending to have continuous variables first */
9688 SCIPsortDownInt(rowinds, nnz);
9689
9690 /* array to store whether a binary variable is in the row (-1) or has been used (1) due to variable bound usage */
9691 SCIP_CALL( SCIPallocCleanBufferArray(scip, &binvarused, nbinvars) );
9692
9693 for( i = nnz - 1; i >= 0 && rowinds[i] < nbinvars; --i )
9694 binvarused[rowinds[i]] = -1;
9695
9696 nnonbinvarsrow = i + 1;
9697 /* determine the bounds to use for transforming the non-binary variables */
9698 for( i = 0; i < nnonbinvarsrow; ++i )
9699 {
9700 SCIP_Bool freevariable;
9701
9702 assert(rowinds[i] >= nbinvars);
9703
9704 SCIP_CALL( determineBoundForSNF(scip, sol, vars, rowcoefs, rowinds, i, binvarused, allowlocal, boundswitch,
9705 bestlb, bestub, bestslb, bestsub, bestlbtype, bestubtype, bestslbtype, bestsubtype, selectedbounds, &freevariable) );
9706
9707 if( freevariable )
9708 {
9709 int j;
9710
9711 /* clear binvarused at indices of binary variables of row */
9712 for( j = nnz - 1; j >= nnonbinvarsrow; --j )
9713 binvarused[rowinds[j]] = 0;
9714
9715 /* clear binvarused at indices of selected variable bounds */
9716 for( j = 0; j < i; ++j )
9717 {
9718 if( selectedbounds[j] == SCIP_BOUNDTYPE_LOWER && bestlbtype[j] >= 0 )
9719 {
9720 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(vars[rowinds[j]]);
9721 binvarused[SCIPvarGetProbindex(vlbvars[bestlbtype[j]])] = 0;
9722 }
9723 else if( selectedbounds[j] == SCIP_BOUNDTYPE_UPPER && bestubtype[j] >= 0 )
9724 {
9725 SCIP_VAR** vubvars = SCIPvarGetVubVars(vars[rowinds[j]]);
9726 binvarused[SCIPvarGetProbindex(vubvars[bestubtype[j]])] = 0;
9727 }
9728 }
9729
9730 /* terminate */
9731 goto TERMINATE;
9732 }
9733 }
9734
9735 *localbdsused = FALSE;
9736 QUAD_ASSIGN_Q(transrhs, rowrhs);
9737 snf->ntransvars = 0;
9738
9739 assert(snf->transvarcoefs != NULL); /* for lint */
9740 assert(snf->transvarvubcoefs != NULL);
9743 assert(snf->aggrconstants != NULL);
9744 assert(snf->aggrcoefscont != NULL);
9745 assert(snf->origcontvars != NULL);
9746 assert(snf->origbinvars != NULL);
9747 assert(snf->aggrcoefsbin != NULL);
9748
9749 /* transform non-binary variables */
9750 for( i = 0; i < nnonbinvarsrow; ++i )
9751 {
9752 SCIP_VAR* var;
9753 SCIP_Real QUAD(rowcoef);
9754 SCIP_Real solval;
9755 int probidx;
9756
9757 probidx = rowinds[i];
9758 var = vars[probidx];
9759 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
9760 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
9761 solval = SCIPgetSolVal(scip, sol, var);
9762
9763 assert(probidx >= nbinvars);
9764
9765 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
9766 {
9767 /* use bestlb to define y'_j */
9768
9769 assert(!SCIPisInfinity(scip, bestsub[i]));
9770 assert(!SCIPisInfinity(scip, - bestlb[i]));
9771 assert(bestsubtype[i] == -1 || bestsubtype[i] == -2);
9772 assert(bestlbtype[i] > -3 && bestlbtype[i] < SCIPvarGetNVlbs(var));
9773
9774 /* store for y_j that bestlb is the bound used to define y'_j and that y'_j is the associated real variable
9775 * in the relaxed set
9776 */
9777 snf->origcontvars[snf->ntransvars] = probidx;
9778
9779 if( bestlbtype[i] < 0 )
9780 {
9781 SCIP_Real QUAD(val);
9782 SCIP_Real QUAD(contsolval);
9783 SCIP_Real QUAD(rowcoeftimesbestsub);
9784
9785 /* use simple lower bound in bestlb = l_j <= y_j <= u_j = bestsub to define
9786 * y'_j = - a_j ( y_j - u_j ) with 0 <= y'_j <= a_j ( u_j - l_j ) x_j and x_j = 1 if a_j > 0
9787 * y'_j = a_j ( y_j - u_j ) with 0 <= y'_j <= - a_j ( u_j - l_j ) x_j and x_j = 1 if a_j < 0,
9788 * put j into the set
9789 * N2 if a_j > 0
9790 * N1 if a_j < 0
9791 * and update the right hand side of the constraint in the relaxation
9792 * rhs = rhs - a_j u_j
9793 */
9794 SCIPquadprecSumDD(val, bestsub[i], -bestlb[i]);
9795 SCIPquadprecProdQQ(val, val, rowcoef);
9796 SCIPquadprecSumDD(contsolval, solval, -bestsub[i]);
9797 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
9798
9799 if( bestlbtype[i] == -2 || bestsubtype[i] == -2 )
9800 *localbdsused = TRUE;
9801
9802 SCIPquadprecProdQD(rowcoeftimesbestsub, rowcoef, bestsub[i]);
9803
9804 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
9805 snf->origbinvars[snf->ntransvars] = -1;
9806 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
9807
9808 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
9809 {
9810 snf->transvarcoefs[snf->ntransvars] = - 1;
9811 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
9812 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
9813 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
9814
9815 /* aggregation information for y'_j */
9816 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestsub);
9817 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
9818 }
9819 else
9820 {
9821 snf->transvarcoefs[snf->ntransvars] = 1;
9822 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
9823 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
9824 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
9825
9826 /* aggregation information for y'_j */
9827 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestsub);
9828 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
9829 }
9830 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestsub);
9831
9832 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
9833 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
9834 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestsub), QUAD_TO_DBL(rowcoef), bestsub[i], QUAD_TO_DBL(transrhs));
9835 }
9836 else
9837 {
9838 SCIP_Real QUAD(rowcoefbinary);
9839 SCIP_Real varsolvalbinary;
9840 SCIP_Real QUAD(val);
9841 SCIP_Real QUAD(contsolval);
9842 SCIP_Real QUAD(rowcoeftimesvlbconst);
9843 int vlbvarprobidx;
9844
9845 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
9846 SCIP_Real* vlbconsts = SCIPvarGetVlbConstants(var);
9847 SCIP_Real* vlbcoefs = SCIPvarGetVlbCoefs(var);
9848
9849 /* use variable lower bound in bestlb = l~_j x_j + d_j <= y_j <= u_j = bestsub to define
9850 * y'_j = - ( a_j ( y_j - d_j ) + c_j x_j ) with 0 <= y'_j <= - ( a_j l~_j + c_j ) x_j if a_j > 0
9851 * y'_j = a_j ( y_j - d_j ) + c_j x_j with 0 <= y'_j <= ( a_j l~_j + c_j ) x_j if a_j < 0,
9852 * where c_j is the coefficient of x_j in the row, put j into the set
9853 * N2 if a_j > 0
9854 * N1 if a_j < 0
9855 * and update the right hand side of the constraint in the relaxation
9856 * rhs = rhs - a_j d_j
9857 */
9858
9859 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[i]]);
9860 assert(binvarused[vlbvarprobidx] == 1);
9861 assert(vlbvarprobidx < nbinvars);
9862
9863 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vlbvarprobidx);
9864 varsolvalbinary = SCIPgetSolVal(scip, sol, vlbvars[bestlbtype[i]]);
9865
9866 SCIPquadprecProdQD(val, rowcoef, vlbcoefs[bestlbtype[i]]);
9867 SCIPquadprecSumQQ(val, val, rowcoefbinary);
9868 {
9869 SCIP_Real QUAD(tmp);
9870
9871 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
9872 SCIPquadprecSumDD(contsolval, solval, - vlbconsts[bestlbtype[i]]);
9873 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
9874 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
9875 }
9876
9877 SCIPquadprecProdQD(rowcoeftimesvlbconst, rowcoef, vlbconsts[bestlbtype[i]]);
9878
9879 /* clear the binvarpos array, since the variable has been processed */
9880 binvarused[vlbvarprobidx] = 0;
9881
9882 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
9883 snf->origbinvars[snf->ntransvars] = vlbvarprobidx;
9884
9885 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
9886 {
9887 snf->transvarcoefs[snf->ntransvars] = - 1;
9888 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
9889 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
9890 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
9891
9892 /* aggregation information for y'_j */
9893 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
9894 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
9895 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvlbconst);
9896 }
9897 else
9898 {
9899 snf->transvarcoefs[snf->ntransvars] = 1;
9900 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
9901 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
9902 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
9903
9904 /* aggregation information for y'_j */
9905 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
9906 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
9907 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvlbconst);
9908 }
9909 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvlbconst);
9910
9911 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
9912 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
9913 snf->ntransvars, SCIPvarGetName(vlbvars[bestlbtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvlbconst), QUAD_TO_DBL(rowcoef),
9914 vlbconsts[bestlbtype[i]], QUAD_TO_DBL(transrhs) );
9915 }
9916 }
9917 else
9918 {
9919 /* use bestub to define y'_j */
9920
9921 assert(!SCIPisInfinity(scip, bestub[i]));
9922 assert(!SCIPisInfinity(scip, - bestslb[i]));
9923 assert(bestslbtype[i] == -1 || bestslbtype[i] == -2);
9924 assert(bestubtype[i] > -3 && bestubtype[i] < SCIPvarGetNVubs(var));
9925
9926 /* store for y_j that y'_j is the associated real variable
9927 * in the relaxed set
9928 */
9929 snf->origcontvars[snf->ntransvars] = probidx;
9930
9931 if( bestubtype[i] < 0 )
9932 {
9933 SCIP_Real QUAD(val);
9934 SCIP_Real QUAD(contsolval);
9935 SCIP_Real QUAD(rowcoeftimesbestslb);
9936
9937 /* use simple upper bound in bestslb = l_j <= y_j <= u_j = bestub to define
9938 * y'_j = a_j ( y_j - l_j ) with 0 <= y'_j <= a_j ( u_j - l_j ) x_j and x_j = 1 if a_j > 0
9939 * y'_j = - a_j ( y_j - l_j ) with 0 <= y'_j <= - a_j ( u_j - l_j ) x_j and x_j = 1 if a_j < 0,
9940 * put j into the set
9941 * N1 if a_j > 0
9942 * N2 if a_j < 0
9943 * and update the right hand side of the constraint in the relaxation
9944 * rhs = rhs - a_j l_j
9945 */
9946 SCIPquadprecSumDD(val, bestub[i], - bestslb[i]);
9947 SCIPquadprecProdQQ(val, val, rowcoef);
9948 SCIPquadprecSumDD(contsolval, solval, - bestslb[i]);
9949 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
9950
9951 if( bestubtype[i] == -2 || bestslbtype[i] == -2 )
9952 *localbdsused = TRUE;
9953
9954 SCIPquadprecProdQD(rowcoeftimesbestslb, rowcoef, bestslb[i]);
9955
9956 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
9957 snf->origbinvars[snf->ntransvars] = -1;
9958 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
9959
9960 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
9961 {
9962 snf->transvarcoefs[snf->ntransvars] = 1;
9963 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
9964 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
9965 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
9966
9967 /* aggregation information for y'_j */
9968 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
9969 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestslb);
9970 }
9971 else
9972 {
9973 snf->transvarcoefs[snf->ntransvars] = - 1;
9974 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
9975 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
9976 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
9977
9978 /* aggregation information for y'_j */
9979 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
9980 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestslb);
9981 }
9982 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestslb);
9983
9984 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., Y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
9985 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
9986 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestslb), QUAD_TO_DBL(rowcoef), bestslb[i], QUAD_TO_DBL(transrhs));
9987 }
9988 else
9989 {
9990 SCIP_Real QUAD(rowcoefbinary);
9991 SCIP_Real varsolvalbinary;
9992 SCIP_Real QUAD(val);
9993 SCIP_Real QUAD(contsolval);
9994 SCIP_Real QUAD(rowcoeftimesvubconst);
9995 int vubvarprobidx;
9996
9997 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
9998 SCIP_Real* vubconsts = SCIPvarGetVubConstants(var);
9999 SCIP_Real* vubcoefs = SCIPvarGetVubCoefs(var);
10000
10001 /* use variable upper bound in bestslb = l_j <= y_j <= u~_j x_j + d_j = bestub to define
10002 * y'_j = a_j ( y_j - d_j ) + c_j x_j with 0 <= y'_j <= ( a_j u~_j + c_j ) x_j if a_j > 0
10003 * y'_j = - ( a_j ( y_j - d_j ) + c_j x_j ) with 0 <= y'_j <= - ( a_j u~_j + c_j ) x_j if a_j < 0,
10004 * where c_j is the coefficient of x_j in the row, put j into the set
10005 * N1 if a_j > 0
10006 * N2 if a_j < 0
10007 * and update the right hand side of the constraint in the relaxation
10008 * rhs = rhs - a_j d_j
10009 */
10010
10011 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[i]]);
10012 assert(binvarused[vubvarprobidx] == 1);
10013 assert(vubvarprobidx < nbinvars);
10014
10015 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vubvarprobidx);
10016 varsolvalbinary = SCIPgetSolVal(scip, sol, vubvars[bestubtype[i]]);
10017
10018 /* clear the binvarpos array, since the variable has been processed */
10019 binvarused[vubvarprobidx] = 0;
10020
10021 SCIPquadprecProdQD(val, rowcoef, vubcoefs[bestubtype[i]]);
10022 SCIPquadprecSumQQ(val, val, rowcoefbinary);
10023 {
10024 SCIP_Real QUAD(tmp);
10025 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
10026 SCIPquadprecSumDD(contsolval, solval, - vubconsts[bestubtype[i]]);
10027 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
10028 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
10029 }
10030
10031 SCIPquadprecProdQD(rowcoeftimesvubconst, rowcoef, vubconsts[bestubtype[i]]);
10032 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
10033 snf->origbinvars[snf->ntransvars] = vubvarprobidx;
10034
10035 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
10036 {
10037 snf->transvarcoefs[snf->ntransvars] = 1;
10038 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
10039 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
10040 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
10041
10042 /* aggregation information for y'_j */
10043 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
10044 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
10045 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvubconst);
10046 }
10047 else
10048 {
10049 snf->transvarcoefs[snf->ntransvars] = - 1;
10050 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
10051 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
10052 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
10053
10054 /* aggregation information for y'_j */
10055 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
10056 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
10057 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvubconst);
10058 }
10059 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvubconst);
10060
10061 /* store for x_j that y'_j is the associated real variable in the 0-1 single node flow relaxation */
10062
10063 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
10064 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
10065 snf->ntransvars, SCIPvarGetName(vubvars[bestubtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvubconst), QUAD_TO_DBL(rowcoef),
10066 vubconsts[bestubtype[i]], QUAD_TO_DBL(transrhs));
10067 }
10068 }
10069
10070 /* make sure the coefficient is not negative due to small numerical rounding errors */
10072 snf->transvarvubcoefs[snf->ntransvars] = MAX(snf->transvarvubcoefs[snf->ntransvars], 0.0);
10073
10074 ++snf->ntransvars;
10075 }
10076
10077 snf->transrhs = QUAD_TO_DBL(transrhs);
10078
10079 /* transform remaining binary variables of row */
10080 for( i = nnonbinvarsrow; i < nnz; ++i )
10081 {
10082 SCIP_VAR* var;
10083 SCIP_Real QUAD(rowcoef);
10084 int probidx;
10085 SCIP_Real val;
10086 SCIP_Real contsolval;
10087 SCIP_Real varsolval;
10088
10089 probidx = rowinds[i];
10090 /* variable should be binary */
10091 assert(probidx >= 0);
10092 assert(probidx < nbinvars);
10093
10094 /* binary variable was processed together with a non-binary variable */
10095 if( binvarused[probidx] == 0 )
10096 continue;
10097
10098 /* binary variable was not processed yet, so the binvarused value sould be -1 */
10099 assert(binvarused[probidx] == -1);
10100
10101 /* set binvarused to zero since it has been processed */
10102 binvarused[probidx] = 0;
10103
10104 var = vars[probidx];
10105 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
10106 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
10107
10108 varsolval = SCIPgetSolVal(scip, sol, var);
10109 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g, %g]>:\n", i, QUAD_TO_DBL(rowcoef), SCIPvarGetName(var), probidx, varsolval,
10111
10112 /* define
10113 * y'_j = c_j x_j with 0 <= y'_j <= c_j x_j if c_j > 0
10114 * y'_j = - c_j x_j with 0 <= y'_j <= - c_j x_j if c_j < 0,
10115 * where c_j is the coefficient of x_j in the row and put j into the set
10116 * N1 if c_j > 0
10117 * N2 if c_j < 0.
10118 */
10119 val = QUAD_TO_DBL(rowcoef);
10120 contsolval = QUAD_TO_DBL(rowcoef) * varsolval;
10121
10122 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
10123 snf->origbinvars[snf->ntransvars] = probidx;
10124 snf->origcontvars[snf->ntransvars] = -1;
10125 snf->aggrcoefscont[snf->ntransvars] = 0.0;
10126 snf->aggrconstants[snf->ntransvars] = 0.0;
10127
10128 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
10129 {
10130 snf->transvarcoefs[snf->ntransvars] = 1;
10131 snf->transvarvubcoefs[snf->ntransvars] = val;
10132 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
10133 snf->transcontvarsolvals[snf->ntransvars] = contsolval;
10134
10135 /* aggregation information for y'_j */
10136 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
10137 }
10138 else
10139 {
10140 snf->transvarcoefs[snf->ntransvars] = - 1;
10141 snf->transvarvubcoefs[snf->ntransvars] = - val;
10142 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
10143 snf->transcontvarsolvals[snf->ntransvars] = - contsolval;
10144
10145 /* aggregation information for y'_j */
10146 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
10147 }
10148
10149 assert(snf->transvarcoefs[snf->ntransvars] == 1 || snf->transvarcoefs[snf->ntransvars] == - 1 );
10151 && SCIPisFeasLE(scip, snf->transbinvarsolvals[snf->ntransvars], 1.0));
10154
10155 SCIPdebugMsg(scip, " --> ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s))\n", snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars,
10157
10158 /* updates number of variables in transformed problem */
10159 snf->ntransvars++;
10160 }
10161
10162 /* construction was successful */
10163 *success = TRUE;
10164
10165#ifdef SCIP_DEBUG
10166 SCIPdebugMsg(scip, "constraint in constructed 0-1 single node flow relaxation: ");
10167 for( i = 0; i < snf->ntransvars; i++ )
10168 {
10169 SCIPdebugMsgPrint(scip, "%s y'_%d ", snf->transvarcoefs[i] == 1 ? "+" : "-", i);
10170 }
10171 SCIPdebugMsgPrint(scip, "<= %g\n", snf->transrhs);
10172#endif
10173
10174 TERMINATE:
10175
10176 SCIPfreeCleanBufferArray(scip, &binvarused);
10177 SCIPfreeBufferArray(scip, &selectedbounds);
10178 SCIPfreeBufferArray(scip, &bestsubtype);
10179 SCIPfreeBufferArray(scip, &bestslbtype);
10180 SCIPfreeBufferArray(scip, &bestubtype);
10181 SCIPfreeBufferArray(scip, &bestlbtype);
10182 SCIPfreeBufferArray(scip, &bestsub);
10183 SCIPfreeBufferArray(scip, &bestslb);
10184 SCIPfreeBufferArray(scip, &bestub);
10185 SCIPfreeBufferArray(scip, &bestlb);
10186
10187 return SCIP_OKAY;
10188}
10189
10190/** allocate buffer arrays for storing the single-node-flow relaxation */
10191static
10193 SCIP* scip, /**< SCIP data structure */
10194 SNF_RELAXATION* snf, /**< pointer to snf relaxation to be destroyed */
10195 int nvars /**< number of active problem variables */
10196 )
10197{
10207
10208 return SCIP_OKAY;
10209}
10210
10211/** free buffer arrays for storing the single-node-flow relaxation */
10212static
10214 SCIP* scip, /**< SCIP data structure */
10215 SNF_RELAXATION* snf /**< pointer to snf relaxation to be destroyed */
10216 )
10217{
10227}
10228
10229/** solve knapsack problem in maximization form with "<" constraint approximately by greedy; if needed, one can provide
10230 * arrays to store all selected items and all not selected items
10231 */
10232static
10234 SCIP* scip, /**< SCIP data structure */
10235 int nitems, /**< number of available items */
10236 SCIP_Real* weights, /**< item weights */
10237 SCIP_Real* profits, /**< item profits */
10238 SCIP_Real capacity, /**< capacity of knapsack */
10239 int* items, /**< item numbers */
10240 int* solitems, /**< array to store items in solution, or NULL */
10241 int* nonsolitems, /**< array to store items not in solution, or NULL */
10242 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
10243 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
10244 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
10245 )
10246{
10247 SCIP_Real* tempsort;
10248 SCIP_Real solitemsweight;
10249 SCIP_Real mediancapacity;
10250 int j;
10251 int i;
10252 int criticalitem;
10253
10254 assert(weights != NULL);
10255 assert(profits != NULL);
10256 assert(SCIPisFeasGE(scip, capacity, 0.0));
10257 assert(!SCIPisInfinity(scip, capacity));
10258 assert(items != NULL);
10259 assert(nitems >= 0);
10260
10261 if( solitems != NULL )
10262 {
10263 *nsolitems = 0;
10264 *nnonsolitems = 0;
10265 }
10266 if( solval != NULL )
10267 *solval = 0.0;
10268
10269 /* allocate memory for temporary array used for sorting; array should contain profits divided by corresponding weights (p_1 / w_1 ... p_n / w_n )*/
10270 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
10271
10272 /* initialize temporary array */
10273 for( i = nitems - 1; i >= 0; --i )
10274 tempsort[i] = profits[i] / weights[i];
10275
10276 /* decrease capacity slightly to make it tighter than the original capacity */
10277 mediancapacity = capacity * (1 - SCIPfeastol(scip));
10278
10279 /* rearrange items around */
10280 SCIPselectWeightedDownRealRealInt(tempsort, profits, items, weights, mediancapacity, nitems, &criticalitem);
10281
10282 /* free temporary array */
10283 SCIPfreeBufferArray(scip, &tempsort);
10284
10285 /* select items as long as they fit into the knapsack */
10286 solitemsweight = 0.0;
10287 for( j = 0; j < nitems && SCIPisFeasLT(scip, solitemsweight + weights[j], capacity); j++ )
10288 {
10289 if( solitems != NULL )
10290 {
10291 solitems[*nsolitems] = items[j];
10292 (*nsolitems)++;
10293 }
10294 if( solval != NULL )
10295 (*solval) += profits[j];
10296 solitemsweight += weights[j];
10297 }
10298
10299 /* continue to put items into the knapsack if they entirely fit */
10300 for( ; j < nitems; j++ )
10301 {
10302 if( SCIPisFeasLT(scip, solitemsweight + weights[j], capacity) )
10303 {
10304 if( solitems != NULL )
10305 {
10306 solitems[*nsolitems] = items[j];
10307 (*nsolitems)++;
10308 }
10309 if( solval != NULL )
10310 (*solval) += profits[j];
10311 solitemsweight += weights[j];
10312 }
10313 else if( solitems != NULL )
10314 {
10315 nonsolitems[*nnonsolitems] = items[j];
10316 (*nnonsolitems)++;
10317 }
10318 }
10319
10320 return SCIP_OKAY;
10321}
10322
10323
10324/** build the flow cover which corresponds to the given exact or approximate solution of KP^SNF; given unfinished
10325 * flow cover contains variables which have been fixed in advance
10326 */
10327static
10329 SCIP* scip, /**< SCIP data structure */
10330 int* coefs, /**< coefficient of all real variables in N1&N2 */
10331 SCIP_Real* vubcoefs, /**< coefficient in vub of all real variables in N1&N2 */
10332 SCIP_Real rhs, /**< right hand side of 0-1 single node flow constraint */
10333 int* solitems, /**< items in knapsack */
10334 int* nonsolitems, /**< items not in knapsack */
10335 int nsolitems, /**< number of items in knapsack */
10336 int nnonsolitems, /**< number of items not in knapsack */
10337 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
10338 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
10339 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
10340 QUAD(SCIP_Real* flowcoverweight), /**< pointer to store weight of flow cover */
10341 SCIP_Real* lambda /**< pointer to store lambda */
10342 )
10343{
10344 int j;
10345 SCIP_Real QUAD(tmp);
10346
10347 assert(scip != NULL);
10348 assert(coefs != NULL);
10349 assert(vubcoefs != NULL);
10350 assert(solitems != NULL);
10351 assert(nonsolitems != NULL);
10352 assert(nsolitems >= 0);
10353 assert(nnonsolitems >= 0);
10354 assert(nflowcovervars != NULL && *nflowcovervars >= 0);
10355 assert(nnonflowcovervars != NULL && *nnonflowcovervars >= 0);
10356 assert(flowcoverstatus != NULL);
10357 assert(QUAD_HI(flowcoverweight) != NULL);
10358 assert(lambda != NULL);
10359
10360 /* get flowcover status for each item */
10361 for( j = 0; j < nsolitems; j++ )
10362 {
10363 /* j in N1 with z°_j = 1 => j in N1\C1 */
10364 if( coefs[solitems[j]] == 1 )
10365 {
10366 flowcoverstatus[solitems[j]] = -1;
10367 (*nnonflowcovervars)++;
10368 }
10369 /* j in N2 with z_j = 1 => j in C2 */
10370 else
10371 {
10372 assert(coefs[solitems[j]] == -1);
10373 flowcoverstatus[solitems[j]] = 1;
10374 (*nflowcovervars)++;
10375 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, -vubcoefs[solitems[j]]);
10376 }
10377 }
10378 for( j = 0; j < nnonsolitems; j++ )
10379 {
10380 /* j in N1 with z°_j = 0 => j in C1 */
10381 if( coefs[nonsolitems[j]] == 1 )
10382 {
10383 flowcoverstatus[nonsolitems[j]] = 1;
10384 (*nflowcovervars)++;
10385 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, vubcoefs[nonsolitems[j]]);
10386 }
10387 /* j in N2 with z_j = 0 => j in N2\C2 */
10388 else
10389 {
10390 assert(coefs[nonsolitems[j]] == -1);
10391 flowcoverstatus[nonsolitems[j]] = -1;
10392 (*nnonflowcovervars)++;
10393 }
10394 }
10395
10396 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
10397 SCIPquadprecSumQD(tmp, *flowcoverweight, -rhs);
10398 *lambda = QUAD_TO_DBL(tmp);
10399}
10400
10401#ifndef NO_EXACT_KNAPSACK
10402
10403/** checks whether the given scalar scales the given value to an integral number with error in the given bounds */
10404static
10406 SCIP_Real val, /**< value that should be scaled to an integral value */
10407 SCIP_Real scalar, /**< scalar that should be tried */
10408 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
10409 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
10410 )
10411{
10412 SCIP_Real sval;
10413 SCIP_Real downval;
10414 SCIP_Real upval;
10415
10416 assert(mindelta <= 0.0);
10417 assert(maxdelta >= 0.0);
10418
10419 sval = val * scalar;
10420 downval = floor(sval);
10421 upval = ceil(sval);
10422
10423 return (SCIPrelDiff(sval, downval) <= maxdelta || SCIPrelDiff(sval, upval) >= mindelta);
10424}
10425
10426/** get integral number with error in the bounds which corresponds to given value scaled by a given scalar;
10427 * should be used in connection with isIntegralScalar()
10428 */
10429static
10430SCIP_Longint getIntegralVal(
10431 SCIP_Real val, /**< value that should be scaled to an integral value */
10432 SCIP_Real scalar, /**< scalar that should be tried */
10433 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
10434 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
10435 )
10436{
10437 SCIP_Real sval;
10438 SCIP_Real upval;
10439 SCIP_Longint intval;
10440
10441 assert(mindelta <= 0.0);
10442 assert(maxdelta >= 0.0);
10443
10444 sval = val * scalar;
10445 upval = ceil(sval);
10446
10447 if( SCIPrelDiff(sval, upval) >= mindelta )
10448 intval = (SCIP_Longint) upval;
10449 else
10450 intval = (SCIP_Longint) (floor(sval));
10451
10452 return intval;
10453}
10454
10455/** get a flow cover (C1, C2) for a given 0-1 single node flow set
10456 * {(x,y) in {0,1}^n x R^n : sum_{j in N1} y_j - sum_{j in N2} y_j <= b, 0 <= y_j <= u_j x_j},
10457 * i.e., get sets C1 subset N1 and C2 subset N2 with sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda and lambda > 0
10458 */
10459static
10461 SCIP* scip, /**< SCIP data structure */
10462 SNF_RELAXATION* snf, /**< the single node flow relaxation */
10463 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
10464 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
10465 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
10466 SCIP_Real* lambda, /**< pointer to store lambda */
10467 SCIP_Bool* found /**< pointer to store whether a cover was found */
10468 )
10469{
10470 SCIP_Real* transprofitsint;
10471 SCIP_Real* transprofitsreal;
10472 SCIP_Real* transweightsreal;
10473 SCIP_Longint* transweightsint;
10474 int* items;
10475 int* itemsint;
10476 int* nonsolitems;
10477 int* solitems;
10478 SCIP_Real QUAD(flowcoverweight);
10479 SCIP_Real QUAD(flowcoverweightafterfix);
10480 SCIP_Real n1itemsweight;
10481 SCIP_Real n2itemsminweight;
10482 SCIP_Real scalar;
10483 SCIP_Real transcapacityreal;
10484#if !defined(NDEBUG) || defined(SCIP_DEBUG)
10485 SCIP_Bool kpexact;
10486#endif
10487 SCIP_Bool scalesuccess;
10488 SCIP_Bool transweightsrealintegral;
10489 SCIP_Longint transcapacityint;
10490 int nflowcovervarsafterfix;
10491 int nitems;
10492 int nn1items;
10493 int nnonflowcovervarsafterfix;
10494 int nnonsolitems;
10495 int nsolitems;
10496 int j;
10497
10498 assert(scip != NULL);
10499 assert(snf->transvarcoefs != NULL);
10501 assert(snf->transvarvubcoefs != NULL);
10502 assert(snf->ntransvars > 0);
10503 assert(nflowcovervars != NULL);
10504 assert(nnonflowcovervars != NULL);
10505 assert(flowcoverstatus != NULL);
10506 assert(lambda != NULL);
10507 assert(found != NULL);
10508
10509 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
10510
10511 /* get data structures */
10513 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
10514 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
10515 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsint, snf->ntransvars) );
10516 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
10517 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
10518 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
10519 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
10520
10521 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
10522 *found = FALSE;
10523 *nflowcovervars = 0;
10524 *nnonflowcovervars = 0;
10525
10526 QUAD_ASSIGN(flowcoverweight, 0.0);
10527 nflowcovervarsafterfix = 0;
10528 nnonflowcovervarsafterfix = 0;
10529 QUAD_ASSIGN(flowcoverweightafterfix, 0.0);
10530#if !defined(NDEBUG) || defined(SCIP_DEBUG)
10531 kpexact = FALSE;
10532#endif
10533
10534 /* fix some variables in advance according to the following fixing strategy
10535 * put j into N1\C1, if j in N1 and x*_j = 0,
10536 * put j into C1, if j in N1 and x*_j = 1,
10537 * put j into C2, if j in N2 and x*_j = 1,
10538 * put j into N2\C2, if j in N2 and x*_j = 0
10539 * and get the set of the remaining variables
10540 */
10541 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
10542 nitems = 0;
10543 nn1items = 0;
10544 n1itemsweight = 0.0;
10545 n2itemsminweight = SCIP_REAL_MAX;
10546 for( j = 0; j < snf->ntransvars; j++ )
10547 {
10548 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
10550 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
10551
10552 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
10553 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
10554 {
10555 flowcoverstatus[j] = -1;
10556 (*nnonflowcovervars)++;
10557 continue;
10558 }
10559
10560 /* x*_j is fractional */
10562 {
10563 items[nitems] = j;
10564 nitems++;
10565 if( snf->transvarcoefs[j] == 1 )
10566 {
10567 n1itemsweight += snf->transvarvubcoefs[j];
10568 nn1items++;
10569 }
10570 else
10571 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
10572 }
10573 /* j is in N1 and x*_j = 0 */
10574 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
10575 {
10576 flowcoverstatus[j] = -1;
10577 (*nnonflowcovervars)++;
10578 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
10579 }
10580 /* j is in N1 and x*_j = 1 */
10581 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
10582 {
10583 flowcoverstatus[j] = 1;
10584 (*nflowcovervars)++;
10585 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
10586 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
10587 }
10588 /* j is in N2 and x*_j = 1 */
10589 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
10590 {
10591 flowcoverstatus[j] = 1;
10592 (*nflowcovervars)++;
10593 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
10594 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
10595 }
10596 /* j is in N2 and x*_j = 0 */
10597 else
10598 {
10599 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
10600 flowcoverstatus[j] = -1;
10601 (*nnonflowcovervars)++;
10602 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
10603 }
10604 }
10605 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
10606 assert(nn1items >= 0);
10607
10608 /* to find a flow cover, transform the following knapsack problem
10609 *
10610 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
10611 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
10612 * z_j in {0,1} for all j in N1 & N2
10613 *
10614 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
10615 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
10616 *
10617 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
10618 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
10619 * z°_j in {0,1} for all j in N1
10620 * z_j in {0,1} for all j in N2,
10621 * and solve it approximately under consideration of the fixing,
10622 * or
10623 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
10624 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
10625 * and multiplying the constraint by a suitable scalar C
10626 *
10627 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
10628 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
10629 * z°_j in {0,1} for all j in N1
10630 * z_j in {0,1} for all j in N2,
10631 * where
10632 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
10633 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
10634 * and solve it exactly under consideration of the fixing.
10635 */
10636 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
10637
10638 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
10639 transweightsrealintegral = TRUE;
10640 for( j = 0; j < nitems; j++ )
10641 {
10642 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
10643
10644 if( !isIntegralScalar(transweightsreal[j], 1.0, -MINDELTA, MAXDELTA) )
10645 transweightsrealintegral = FALSE;
10646
10647 if( snf->transvarcoefs[items[j]] == 1 )
10648 {
10649 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
10650 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
10651 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
10652 }
10653 else
10654 {
10655 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
10656 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
10657 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
10658 }
10659 }
10660 /* get capacity of knapsack constraint in KP^SNF_rat */
10661 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight;
10662 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
10663 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
10664
10665 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
10666 * is less than or equal to zero
10667 */
10668 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
10669 {
10670 assert(!(*found));
10671 goto TERMINATE;
10672 }
10673
10674 /* KP^SNF_rat has been solved by fixing some variables in advance */
10675 assert(nitems >= 0);
10676 if( nitems == 0)
10677 {
10678 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
10679 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
10680 *lambda = QUAD_TO_DBL(flowcoverweight);
10681 *found = TRUE;
10682 goto TERMINATE;
10683 }
10684
10685 /* Use the following strategy
10686 * solve KP^SNF_int exactly, if a suitable factor C is found and (nitems*capacity) <= MAXDYNPROGSPACE,
10687 * solve KP^SNF_rat approximately, otherwise
10688 */
10689
10690 /* find a scaling factor C */
10691 if( transweightsrealintegral )
10692 {
10693 /* weights are already integral */
10694 scalar = 1.0;
10695 scalesuccess = TRUE;
10696 }
10697 else
10698 {
10699 scalesuccess = FALSE;
10700 SCIP_CALL( SCIPcalcIntegralScalar(transweightsreal, nitems, -MINDELTA, MAXDELTA, MAXDNOM, MAXSCALE, &scalar,
10701 &scalesuccess) );
10702 }
10703
10704 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
10705 nsolitems = -1;
10706 nnonsolitems = -1;
10707
10708 /* suitable factor C was found*/
10709 if( scalesuccess )
10710 {
10711 SCIP_Real tmp1;
10712 SCIP_Real tmp2;
10713
10714 /* transform KP^SNF to KP^SNF_int */
10715 for( j = 0; j < nitems; ++j )
10716 {
10717 transweightsint[j] = getIntegralVal(transweightsreal[j], scalar, -MINDELTA, MAXDELTA);
10718 transprofitsint[j] = transprofitsreal[j];
10719 itemsint[j] = items[j];
10720 }
10721 if( isIntegralScalar(transcapacityreal, scalar, -MINDELTA, MAXDELTA) )
10722 {
10723 transcapacityint = getIntegralVal(transcapacityreal, scalar, -MINDELTA, MAXDELTA);
10724 transcapacityint -= 1;
10725 }
10726 else
10727 transcapacityint = (SCIP_Longint) (transcapacityreal * scalar);
10728 nflowcovervarsafterfix = *nflowcovervars;
10729 nnonflowcovervarsafterfix = *nnonflowcovervars;
10730 QUAD_ASSIGN_Q(flowcoverweightafterfix, flowcoverweight);
10731
10732 tmp1 = (SCIP_Real) (nitems + 1);
10733 tmp2 = (SCIP_Real) ((transcapacityint) + 1);
10734 if( transcapacityint * nitems <= MAXDYNPROGSPACE && tmp1 * tmp2 <= INT_MAX / 8.0)
10735 {
10736 SCIP_Bool success;
10737
10738 /* solve KP^SNF_int by dynamic programming */
10739 SCIP_CALL( SCIPsolveKnapsackExactly(scip, nitems, transweightsint, transprofitsint, transcapacityint,
10740 itemsint, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL, &success) );
10741
10742 if( !success )
10743 {
10744 /* solve KP^SNF_rat approximately */
10745 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal,
10746 transcapacityreal, items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
10747 }
10748#if !defined(NDEBUG) || defined(SCIP_DEBUG)
10749 else
10750 kpexact = TRUE;
10751#endif
10752 }
10753 else
10754 {
10755 /* solve KP^SNF_rat approximately */
10756 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
10757 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
10758 assert(!kpexact);
10759 }
10760 }
10761 else
10762 {
10763 /* solve KP^SNF_rat approximately */
10764 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
10765 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
10766 assert(!kpexact);
10767 }
10768
10769 assert(nsolitems != -1);
10770 assert(nnonsolitems != -1);
10771
10772 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
10773 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
10774 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
10775 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
10776 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
10777
10778 /* if the found structure is not a flow cover, because of scaling, solve KP^SNF_rat approximately */
10779 if( SCIPisFeasLE(scip, *lambda, 0.0) )
10780 {
10781 assert(kpexact);
10782
10783 /* solve KP^SNF_rat approximately */
10784 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
10785 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
10786#ifdef SCIP_DEBUG /* this time only for SCIP_DEBUG, because only then, the variable is used again */
10787 kpexact = FALSE;
10788#endif
10789
10790 /* build the flow cover from the solution of KP^SNF_rat and the fixing */
10791 *nflowcovervars = nflowcovervarsafterfix;
10792 *nnonflowcovervars = nnonflowcovervarsafterfix;
10793 QUAD_ASSIGN_Q(flowcoverweight, flowcoverweightafterfix);
10794
10795 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
10796 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
10797 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
10798 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
10799 }
10800 *found = SCIPisFeasGT(scip, *lambda, 0.0);
10801
10802 TERMINATE:
10803 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
10804#ifdef SCIP_DEBUG
10805 if( *found )
10806 {
10807 SCIPdebugMsg(scip, "2. %s solution:\n", kpexact ? "exact" : "approximate");
10808 for( j = 0; j < snf->ntransvars; j++ )
10809 {
10810 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
10811 {
10812 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
10813 }
10814 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
10815 {
10816 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
10817 }
10818 }
10819 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
10820 }
10821#endif
10822
10823 /* free data structures */
10824 SCIPfreeBufferArray(scip, &nonsolitems);
10825 SCIPfreeBufferArray(scip, &solitems);
10826 SCIPfreeBufferArray(scip, &transweightsint);
10827 SCIPfreeBufferArray(scip, &transweightsreal);
10828 SCIPfreeBufferArray(scip, &transprofitsint);
10829 SCIPfreeBufferArray(scip, &transprofitsreal);
10830 SCIPfreeBufferArray(scip, &itemsint);
10831 SCIPfreeBufferArray(scip, &items);
10832
10833 return SCIP_OKAY;
10834}
10835
10836#else
10837
10838/** get a flow cover \f$(C1, C2)\f$ for a given 0-1 single node flow set
10839 * \f${(x,y) in {0,1}^n x R^n : sum_{j in N1} y_j - sum_{j in N2} y_j <= b, 0 <= y_j <= u_j x_j}\f$,
10840 * i.e., get sets \f$ C1 \subset N1 \f$ and \f$ C2 \subset N2 \f$ with
10841 * \f$ \sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda \f$ and \f$ lambda > 0 \f$
10842 */
10843static
10845 SCIP* scip, /**< SCIP data structure */
10846 SNF_RELAXATION* snf, /**< the 0-1 single node flow relaxation */
10847 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
10848 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
10849 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
10850 SCIP_Real* lambda, /**< pointer to store lambda */
10851 SCIP_Bool* found /**< pointer to store whether a cover was found */
10852 )
10853{
10854 SCIP_Real* transprofitsreal;
10855 SCIP_Real* transweightsreal;
10856 SCIP_Longint* transweightsint;
10857 int* items;
10858 int* itemsint;
10859 int* nonsolitems;
10860 int* solitems;
10861 SCIP_Real QUAD(flowcoverweight);
10862 SCIP_Real n1itemsweight;
10863 SCIP_Real n2itemsminweight;
10864 SCIP_Real transcapacityreal;
10865 int nitems;
10866#ifndef NDEBUG
10867 int nn1items = 0;
10868#endif
10869 int nnonsolitems;
10870 int nsolitems;
10871 int j;
10872
10873 assert(scip != NULL);
10874 assert(snf->transvarcoefs != NULL);
10876 assert(snf->transvarvubcoefs != NULL);
10877 assert(snf->ntransvars > 0);
10878 assert(nflowcovervars != NULL);
10879 assert(nnonflowcovervars != NULL);
10880 assert(flowcoverstatus != NULL);
10881 assert(lambda != NULL);
10882 assert(found != NULL);
10883
10884 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
10885
10886 /* get data structures */
10888 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
10889 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
10890 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
10891 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
10892 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
10893 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
10894
10895 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
10896 *found = FALSE;
10897 *nflowcovervars = 0;
10898 *nnonflowcovervars = 0;
10899
10900 QUAD_ASSIGN(flowcoverweight, 0.0);
10901
10902 /* fix some variables in advance according to the following fixing strategy
10903 * put j into N1\C1, if j in N1 and x*_j = 0,
10904 * put j into C1, if j in N1 and x*_j = 1,
10905 * put j into C2, if j in N2 and x*_j = 1,
10906 * put j into N2\C2, if j in N2 and x*_j = 0
10907 * and get the set of the remaining variables
10908 */
10909 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
10910 nitems = 0;
10911 n1itemsweight = 0.0;
10912 n2itemsminweight = SCIP_REAL_MAX;
10913 for( j = 0; j < snf->ntransvars; j++ )
10914 {
10915 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
10917 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
10918
10919 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
10920 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
10921 {
10922 flowcoverstatus[j] = -1;
10923 (*nnonflowcovervars)++;
10924 continue;
10925 }
10926
10927 /* x*_j is fractional */
10929 {
10930 items[nitems] = j;
10931 nitems++;
10932 if( snf->transvarcoefs[j] == 1 )
10933 {
10934 n1itemsweight += snf->transvarvubcoefs[j];
10935#ifndef NDEBUG
10936 nn1items++;
10937#endif
10938 }
10939 else
10940 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
10941 }
10942 /* j is in N1 and x*_j = 0 */
10943 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
10944 {
10945 flowcoverstatus[j] = -1;
10946 (*nnonflowcovervars)++;
10947 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
10948 }
10949 /* j is in N1 and x*_j = 1 */
10950 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
10951 {
10952 flowcoverstatus[j] = 1;
10953 (*nflowcovervars)++;
10954 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
10955 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
10956 }
10957 /* j is in N2 and x*_j = 1 */
10958 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
10959 {
10960 flowcoverstatus[j] = 1;
10961 (*nflowcovervars)++;
10962 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
10963 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
10964 }
10965 /* j is in N2 and x*_j = 0 */
10966 else
10967 {
10968 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
10969 flowcoverstatus[j] = -1;
10970 (*nnonflowcovervars)++;
10971 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
10972 }
10973 }
10974 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
10975 assert(nn1items >= 0);
10976
10977 /* to find a flow cover, transform the following knapsack problem
10978 *
10979 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
10980 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
10981 * z_j in {0,1} for all j in N1 & N2
10982 *
10983 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
10984 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
10985 *
10986 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
10987 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
10988 * z°_j in {0,1} for all j in N1
10989 * z_j in {0,1} for all j in N2,
10990 * and solve it approximately under consideration of the fixing,
10991 * or
10992 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
10993 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
10994 * and multiplying the constraint by a suitable scalar C
10995 *
10996 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
10997 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
10998 * z°_j in {0,1} for all j in N1
10999 * z_j in {0,1} for all j in N2,
11000 * where
11001 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
11002 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
11003 * and solve it exactly under consideration of the fixing.
11004 */
11005 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
11006
11007 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
11008 for( j = 0; j < nitems; j++ )
11009 {
11010 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
11011
11012 if( snf->transvarcoefs[items[j]] == 1 )
11013 {
11014 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
11015 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
11016 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
11017 }
11018 else
11019 {
11020 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
11021 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
11022 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
11023 }
11024 }
11025 /* get capacity of knapsack constraint in KP^SNF_rat */
11026 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight; /*lint !e644*/
11027 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
11028 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
11029
11030 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
11031 * is less than or equal to zero
11032 */
11033 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
11034 {
11035 assert(!(*found));
11036 goto TERMINATE;
11037 }
11038
11039 /* KP^SNF_rat has been solved by fixing some variables in advance */
11040 assert(nitems >= 0);
11041 if( nitems == 0 )
11042 {
11043 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
11044 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
11045 *lambda = QUAD_TO_DBL(flowcoverweight);
11046 *found = TRUE;
11047 goto TERMINATE;
11048 }
11049
11050 /* Solve the KP^SNF_rat approximately */
11051
11052 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
11053 nsolitems = -1;
11054 nnonsolitems = -1;
11055
11056 /* suitable factor C was found*/
11057 /* solve KP^SNF_rat approximately */
11058 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
11059 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
11060
11061 assert(nsolitems != -1);
11062 assert(nnonsolitems != -1);
11063
11064 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
11065 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
11066 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
11067 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
11068 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
11069
11070 *found = SCIPisFeasGT(scip, *lambda, 0.0);
11071
11072 TERMINATE:
11073 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
11074#ifdef SCIP_DEBUG
11075 if( *found )
11076 {
11077 SCIPdebugMsg(scip, "2. approximate solution:\n");
11078 for( j = 0; j < snf->ntransvars; j++ )
11079 {
11080 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
11081 {
11082 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
11083 }
11084 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
11085 {
11086 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
11087 }
11088 }
11089 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
11090 }
11091#endif
11092
11093 /* free data structures */
11094 SCIPfreeBufferArray(scip, &nonsolitems);
11095 SCIPfreeBufferArray(scip, &solitems);
11096 SCIPfreeBufferArray(scip, &transweightsint);
11097 SCIPfreeBufferArray(scip, &transweightsreal);
11098 SCIPfreeBufferArray(scip, &transprofitsreal);
11099 SCIPfreeBufferArray(scip, &itemsint);
11100 SCIPfreeBufferArray(scip, &items);
11101
11102 return SCIP_OKAY;
11103}
11104
11105#endif
11106
11107/** evaluate the super-additive lifting function for the lifted simple generalized flowcover inequalities
11108 * for a given value \f$ x \in \{ u_j \mid j \in C- \} \f$.
11109 */
11110static
11112 SCIP* scip, /**< SCIP data structure */
11113 LIFTINGDATA* liftingdata, /**< lifting data to use */
11114 SCIP_Real x /**< value where to evaluate lifting function */
11115 )
11116{
11117 SCIP_Real QUAD(tmp);
11118 SCIP_Real xpluslambda;
11119 int i;
11120
11121 assert( liftingdata != NULL );
11122
11123 xpluslambda = x + liftingdata->lambda;
11124
11125 i = 0;
11126 while( i < liftingdata->r && SCIPisGT(scip, xpluslambda, liftingdata->M[i+1]) )
11127 ++i;
11128
11129 if( i < liftingdata->t )
11130 {
11131 if( SCIPisLE(scip, liftingdata->M[i], x) )
11132 {
11133 assert(SCIPisLE(scip, xpluslambda, liftingdata->M[i+1]));
11134 return i * liftingdata->lambda;
11135 }
11136
11137 assert(i > 0 && SCIPisLE(scip, liftingdata->M[i], xpluslambda) && x <= liftingdata->M[i]);
11138
11139 /* return x - liftingdata->M[i] + i * liftingdata->lambda */
11140 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
11141 SCIPquadprecSumQD(tmp, tmp, x);
11142 SCIPquadprecSumQD(tmp, tmp, -liftingdata->M[i]);
11143 return QUAD_TO_DBL(tmp);
11144 }
11145
11146 if( i < liftingdata->r )
11147 {
11148 assert(!SCIPisInfinity(scip, liftingdata->mp));
11149
11150 /* p = liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml; */
11151 SCIPquadprecSumDD(tmp, liftingdata->m[i], -liftingdata->mp);
11152 SCIPquadprecSumQD(tmp, tmp, -liftingdata->ml);
11153 SCIPquadprecSumQD(tmp, tmp, liftingdata->lambda);
11154
11155 /* p = MAX(0.0, p); */
11156 if( QUAD_HI(tmp) < 0.0 )
11157 {
11158 QUAD_ASSIGN(tmp, 0.0);
11159 }
11160
11161 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
11162 SCIPquadprecSumQD(tmp, tmp, liftingdata->ml);
11163
11164 if( SCIPisLT(scip, QUAD_TO_DBL(tmp), xpluslambda) )
11165 return i * liftingdata->lambda;
11166
11167 assert(SCIPisFeasLE(scip, liftingdata->M[i], xpluslambda) &&
11168 SCIPisFeasLE(scip, xpluslambda, liftingdata->M[i] + liftingdata->ml +
11169 MAX(0.0, liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml)));
11170
11171 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
11172 SCIPquadprecSumQD(tmp, tmp, x);
11173 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[i]);
11174 return QUAD_TO_DBL(tmp);
11175 }
11176
11177 assert(i == liftingdata->r && SCIPisLE(scip, liftingdata->M[liftingdata->r], xpluslambda));
11178
11179 SCIPquadprecProdDD(tmp, liftingdata->r, liftingdata->lambda);
11180 SCIPquadprecSumQD(tmp, tmp, x);
11181 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[liftingdata->r]);
11182 return QUAD_TO_DBL(tmp);
11183}
11184
11185/** computes
11186 * \f[
11187 * (\alpha_j, \beta_j) =
11188 * \begin{cases}
11189 * (0, 0) &\quad\text{if} M_i \leq u_j \leq M_{i+1} - \lambda \\
11190 * (1, M_i - i \lambda) &\quad\text{if} M_i − \lambda < u_j < M_i \\
11191 * \end{cases}
11192 * \f]
11193 */
11194static
11196 SCIP* scip, /**< SCIP data structure */
11197 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
11198 SCIP_Real vubcoef, /**< vub coefficient to get alpha and beta for */
11199 int* alpha, /**< get alpha coefficient for lifting */
11200 SCIP_Real* beta /**< get beta coefficient for lifting */
11201 )
11202{
11203 SCIP_Real vubcoefpluslambda;
11204 int i;
11205
11206 vubcoefpluslambda = vubcoef + liftingdata->lambda;
11207
11208 i = 0;
11209 while( i < liftingdata->r && SCIPisGT(scip, vubcoefpluslambda, liftingdata->M[i+1]) )
11210 ++i;
11211
11212 if( SCIPisLT(scip, vubcoef, liftingdata->M[i]) )
11213 {
11214 SCIP_Real QUAD(tmp);
11215 assert(liftingdata->M[i] < vubcoefpluslambda);
11216 *alpha = 1;
11217 SCIPquadprecProdDD(tmp, -i, liftingdata->lambda);
11218 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
11219 *beta = QUAD_TO_DBL(tmp);
11220 }
11221 else
11222 {
11223 assert(SCIPisSumLE(scip, liftingdata->M[i], vubcoef));
11224 assert(i == liftingdata->r || SCIPisLE(scip, vubcoefpluslambda, liftingdata->M[i+1]));
11225 *alpha = 0;
11226 *beta = 0.0;
11227 }
11228}
11229
11230/** compute relevant data for performing the sequence independent lifting */
11231static
11233 SCIP* scip, /**< SCIP data structure */
11234 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
11235 int* transvarflowcoverstatus, /**< pointer to store whether non-binary var is in L2 (2) or not (-1 or 1) */
11236 SCIP_Real lambda, /**< lambda */
11237 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
11238 SCIP_Bool* valid /**< is the lifting data valid */
11239 )
11240{
11241 int i;
11242 SCIP_Real QUAD(tmp);
11243 SCIP_Real QUAD(sumN2mC2LE);
11244 SCIP_Real QUAD(sumN2mC2GT);
11245 SCIP_Real QUAD(sumC1LE);
11246 SCIP_Real QUAD(sumC2);
11247
11248#ifndef NDEBUG
11249 /* for debugging */
11250 liftingdata->m = NULL;
11251 liftingdata->M = NULL;
11252 liftingdata->lambda = SCIP_INVALID;
11253 liftingdata->t = 0;
11254 liftingdata->mp = SCIP_INVALID;
11255#endif
11256
11257 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->m, snf->ntransvars) );
11258
11259 liftingdata->r = 0;
11260 QUAD_ASSIGN(sumN2mC2LE, 0.0);
11261 QUAD_ASSIGN(sumC1LE, 0.0);
11262 QUAD_ASSIGN(sumN2mC2GT, 0.0);
11263 QUAD_ASSIGN(sumC2, 0.0);
11264
11265 liftingdata->mp = SCIPinfinity(scip);
11266
11267 *valid = FALSE;
11268
11269 for( i = 0; i < snf->ntransvars; ++i )
11270 {
11271 int s = (snf->transvarcoefs[i] + 1) + (transvarflowcoverstatus[i] + 1)/2;
11272
11273 switch(s)
11274 {
11275 case 0: /* var is in N2 \ C2 */
11276 assert(snf->transvarvubcoefs[i] >= 0.0);
11277 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == -1);
11278
11279 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
11280 {
11281 SCIPquadprecSumQD(sumN2mC2GT, sumN2mC2GT, snf->transvarvubcoefs[i]);
11282 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
11283 }
11284 else
11285 {
11286 SCIPquadprecSumQD(sumN2mC2LE, sumN2mC2LE, snf->transvarvubcoefs[i]);
11287 }
11288 break;
11289 case 1: /* var is in C2 */
11290 assert(snf->transvarvubcoefs[i] > 0.0);
11291 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == 1);
11292
11293 SCIPquadprecSumQD(sumC2, sumC2, snf->transvarvubcoefs[i]);
11294 break;
11295 case 3: /* var is in C1 */
11296 assert(snf->transvarcoefs[i] == 1 && transvarflowcoverstatus[i] == 1);
11297 assert(snf->transvarvubcoefs[i] > 0.0);
11298
11299 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
11300 {
11301 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
11302 liftingdata->mp = MIN(liftingdata->mp, snf->transvarvubcoefs[i]);
11303 }
11304 else
11305 {
11306 SCIPquadprecSumQD(sumC1LE, sumC1LE, snf->transvarvubcoefs[i]);
11307 }
11308 break;
11309 default:
11310 assert(s == 2);
11311 continue;
11312 }
11313 }
11314
11315 if( SCIPisInfinity(scip, liftingdata->mp) )
11316 {
11317 SCIPfreeBufferArray(scip, &liftingdata->m);
11318 return SCIP_OKAY;
11319 }
11320
11321 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->M, liftingdata->r + 1) );
11322
11323 *valid = TRUE;
11324
11325 SCIPquadprecSumQQ(tmp, sumC1LE, sumN2mC2LE);
11326 liftingdata->ml = MIN(lambda, QUAD_TO_DBL(tmp));
11327 SCIPquadprecSumQD(tmp, sumC2, snf->transrhs);
11328 liftingdata->d1 = QUAD_TO_DBL(tmp);
11329 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2GT);
11330 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2LE);
11331 liftingdata->d2 = QUAD_TO_DBL(tmp);
11332
11333 SCIPsortDownReal(liftingdata->m, liftingdata->r);
11334
11335 /* compute M[i] = sum_{i \in [1,r]} m[i] where m[*] is sorted decreasingly and M[0] = 0 */
11336 QUAD_ASSIGN(tmp, 0.0);
11337 for( i = 0; i < liftingdata->r; ++i)
11338 {
11339 liftingdata->M[i] = QUAD_TO_DBL(tmp);
11340 SCIPquadprecSumQD(tmp, tmp, liftingdata->m[i]);
11341 }
11342
11343 liftingdata->M[liftingdata->r] = QUAD_TO_DBL(tmp);
11344
11345 SCIP_UNUSED( SCIPsortedvecFindDownReal(liftingdata->m, liftingdata->mp, liftingdata->r, &liftingdata->t) );
11346 assert(liftingdata->m[liftingdata->t] == liftingdata->mp || SCIPisInfinity(scip, liftingdata->mp)); /*lint !e777*/
11347
11348 /* compute t largest index sucht that m_t = mp
11349 * note that liftingdata->m[t-1] == mp due to zero based indexing of liftingdata->m
11350 */
11351 ++liftingdata->t;
11352 while( liftingdata->t < liftingdata->r && liftingdata->m[liftingdata->t] == liftingdata->mp ) /*lint !e777*/
11353 ++liftingdata->t;
11354
11355 liftingdata->lambda = lambda;
11356
11357 return SCIP_OKAY;
11358}
11359
11360/** destroy data used for the sequence independent lifting */
11361static
11363 SCIP* scip, /**< SCIP data structure */
11364 LIFTINGDATA* liftingdata /**< pointer to lifting function struct */
11365 )
11366{
11367 SCIPfreeBufferArray(scip, &liftingdata->M);
11368 SCIPfreeBufferArray(scip, &liftingdata->m);
11369}
11370
11371/** store the simple lifted flowcover cut defined by the given data in the given arrays
11372 * the array for storing the cut coefficients must be all zeros
11373 */
11374static
11376 SCIP* scip, /**< SCIP data structure */
11377 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
11378 SCIP_AGGRROW* aggrrow, /**< aggrrow used to construct SNF relaxation */
11379 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
11380 SCIP_Real lambda, /**< lambda */
11381 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
11382 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
11383 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
11384 int* nnz, /**< number of non-zeros in cut */
11385 SCIP_Bool* success /**< was the cut successfully generated */
11386 )
11387{
11388 SCIP_Real QUAD(rhs);
11389 LIFTINGDATA liftingdata;
11390 int i;
11391
11392 SCIP_CALL( computeLiftingData(scip, snf, flowcoverstatus, lambda, &liftingdata, success) );
11393 if( ! *success )
11394 return SCIP_OKAY;
11395 assert( liftingdata.m != NULL );
11396 assert( liftingdata.M != NULL );
11397 assert( liftingdata.lambda != SCIP_INVALID ); /*lint !e777*/
11398 assert( liftingdata.r >= 0 );
11399 assert( liftingdata.t >= 0 );
11400 assert( liftingdata.mp != SCIP_INVALID ); /*lint !e777*/
11401
11402 QUAD_ASSIGN(rhs, liftingdata.d1);
11403
11404 *nnz = 0;
11405
11406 for( i = 0; i < snf->ntransvars; ++i )
11407 {
11408 int s = (snf->transvarcoefs[i] + 1) + (flowcoverstatus[i] + 1)/2;
11409
11410 switch(s)
11411 {
11412 case 0: /* var is in N2 \ C2 */
11413 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
11414 {
11415 /* var is in L- */
11416 if( snf->origbinvars[i] != -1 )
11417 {
11418 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11419 cutinds[*nnz] = snf->origbinvars[i];
11420 cutcoefs[snf->origbinvars[i]] = -lambda;
11421 ++(*nnz);
11422 }
11423 else
11424 {
11425 SCIPquadprecSumQD(rhs, rhs, lambda);
11426 }
11427 }
11428 else
11429 {
11430 /* var is in L-- */
11431 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
11432 {
11433 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
11434 cutinds[*nnz] = snf->origcontvars[i];
11435 cutcoefs[snf->origcontvars[i]] = -snf->aggrcoefscont[i];
11436 ++(*nnz);
11437 }
11438
11439 if( snf->origbinvars[i] != -1 && snf->aggrcoefsbin[i] != 0.0 )
11440 {
11441 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11442 cutinds[*nnz] = snf->origbinvars[i];
11443 cutcoefs[snf->origbinvars[i]] = -snf->aggrcoefsbin[i];
11444 ++(*nnz);
11445 }
11446
11447 SCIPquadprecSumQD(rhs, rhs, snf->aggrconstants[i]);
11448 }
11449 break;
11450 case 1: /* var is in C2 */
11451 {
11452 assert(snf->transvarvubcoefs[i] > 0.0);
11453 assert(snf->transvarcoefs[i] == -1 && flowcoverstatus[i] == 1);
11454
11455 if( snf->origbinvars[i] != -1 )
11456 {
11457 SCIP_Real liftedbincoef = evaluateLiftingFunction(scip, &liftingdata, snf->transvarvubcoefs[i]);
11458 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11459 if( liftedbincoef != 0.0 )
11460 {
11461 cutinds[*nnz] = snf->origbinvars[i];
11462 cutcoefs[snf->origbinvars[i]] = -liftedbincoef;
11463 ++(*nnz);
11464 SCIPquadprecSumQD(rhs, rhs, -liftedbincoef);
11465 }
11466 }
11467 break;
11468 }
11469 case 2: /* var is in N1 \ C1 */
11470 {
11471 int alpha;
11472 SCIP_Real beta;
11473
11474 assert(snf->transvarcoefs[i] == 1 && flowcoverstatus[i] == -1);
11475
11476 getAlphaAndBeta(scip, &liftingdata, snf->transvarvubcoefs[i], &alpha, &beta);
11477 assert(alpha == 0 || alpha == 1);
11478
11479 if( alpha == 1 )
11480 {
11481 SCIP_Real QUAD(binvarcoef);
11482 assert(beta > 0.0);
11483
11484 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
11485 {
11486 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
11487 cutinds[*nnz] = snf->origcontvars[i];
11488 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
11489 ++(*nnz);
11490 }
11491
11492 SCIPquadprecSumDD(binvarcoef, snf->aggrcoefsbin[i], -beta);
11493 if( snf->origbinvars[i] != -1 )
11494 {
11495 SCIP_Real tmp;
11496
11497 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11498
11499 tmp = QUAD_TO_DBL(binvarcoef);
11500 if( tmp != 0.0 )
11501 {
11502 cutinds[*nnz] = snf->origbinvars[i];
11503 cutcoefs[snf->origbinvars[i]] = tmp;
11504 ++(*nnz);
11505 }
11506 }
11507 else
11508 {
11509 SCIPquadprecSumQQ(rhs, rhs, -binvarcoef);
11510 }
11511
11512 SCIPquadprecSumQD(rhs, rhs, -snf->aggrconstants[i]);
11513 }
11514 break;
11515 }
11516 case 3: /* var is in C1 */
11517 {
11518 SCIP_Real bincoef = snf->aggrcoefsbin[i];
11519 SCIP_Real constant = snf->aggrconstants[i];
11520
11521 if( snf->origbinvars[i] != -1 && SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
11522 {
11523 /* var is in C++ */
11524 SCIP_Real QUAD(tmp);
11525 SCIP_Real QUAD(tmp2);
11526
11527 SCIPquadprecSumDD(tmp, snf->transvarvubcoefs[i], -lambda);
11528
11529 SCIPquadprecSumQD(tmp2, tmp, constant);
11530 constant = QUAD_TO_DBL(tmp2);
11531
11532 SCIPquadprecSumQD(tmp2, tmp, -bincoef);
11533 bincoef = -QUAD_TO_DBL(tmp2);
11534 }
11535
11536 if( snf->origbinvars[i] != -1 && bincoef != 0.0 )
11537 {
11538 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11539 cutinds[*nnz] = snf->origbinvars[i];
11540 cutcoefs[snf->origbinvars[i]] = bincoef;
11541 ++(*nnz);
11542 }
11543
11544 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
11545 {
11546 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
11547 cutinds[*nnz] = snf->origcontvars[i];
11548 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
11549 ++(*nnz);
11550 }
11551
11552 SCIPquadprecSumQD(rhs, rhs, -constant);
11553 break;
11554 }
11555 default:
11556 SCIPABORT();
11557 }
11558 }
11559
11560 destroyLiftingData(scip, &liftingdata);
11561
11562 {
11563 SCIP_ROW** rows = SCIPgetLPRows(scip);
11564 for( i = 0; i < aggrrow->nrows; ++i )
11565 {
11566 SCIP_ROW* row;
11567 SCIP_Real rowlhs;
11568 SCIP_Real rowrhs;
11569 SCIP_Real slackub;
11570 SCIP_Real slackcoef;
11571
11572 slackcoef = aggrrow->rowweights[i] * aggrrow->slacksign[i];
11573 assert(slackcoef != 0.0);
11574
11575 /* positive slack was implicitly handled in flow cover separation */
11576 if( slackcoef > 0.0 )
11577 continue;
11578
11579 row = rows[aggrrow->rowsinds[i]];
11580
11581 /* add the slack's definition multiplied with its coefficient to the cut */
11582 SCIP_CALL( varVecAddScaledRowCoefs(cutinds, cutcoefs, nnz, row, -aggrrow->rowweights[i]) );
11583
11584 /* retrieve sides of row */
11585 rowlhs = row->lhs - row->constant;
11586 rowrhs = row->rhs - row->constant;
11587
11588 if( row->integral )
11589 {
11590 rowrhs = SCIPfloor(scip, rowrhs);
11591 rowlhs = SCIPceil(scip, rowlhs);
11592 }
11593
11594 slackub = rowrhs - rowlhs;
11595
11596 /* move slack's constant to the right hand side, and add lambda to the right hand side if the
11597 * upper bound of the slack is larger than lambda, since then an artifical binary variable
11598 * for the slack would get coefficient -lambda
11599 */
11600 if( aggrrow->slacksign[i] == +1 )
11601 {
11602 SCIP_Real rhsslack;
11603 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
11604 assert(!SCIPisInfinity(scip, row->rhs));
11605
11606 rhsslack = rowrhs - SCIPgetRowMinActivity(scip, row);
11607 slackub = -aggrrow->rowweights[i] * MIN(rhsslack, slackub);
11608
11609 if( SCIPisGE(scip, slackub, lambda) )
11610 SCIPquadprecSumQD(rhs, rhs, lambda);
11611
11612 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowrhs);
11613 }
11614 else
11615 {
11616 SCIP_Real lhsslack;
11617 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
11618 assert(!SCIPisInfinity(scip, -row->lhs));
11619
11620 lhsslack = SCIPgetRowMaxActivity(scip, row) - rowlhs;
11621 slackub = aggrrow->rowweights[i] * MIN(lhsslack, slackub);
11622
11623 if( SCIPisGE(scip, slackub, lambda) )
11624 SCIPquadprecSumQD(rhs, rhs, lambda);
11625
11626 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowlhs);
11627 }
11628 }
11629 }
11630
11631 *cutrhs = QUAD_TO_DBL(rhs);
11632
11633 /* relax rhs to zero, if it's very close to 0 */
11634 if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
11635 *cutrhs = 0.0;
11636
11637 return SCIP_OKAY;
11638}
11639
11640/** calculates a lifted simple generalized flow cover cut out of the weighted sum of LP rows given by an aggregation row; the
11641 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
11642 * participate in the cut.
11643 * For further details we refer to:
11644 *
11645 * Gu, Z., Nemhauser, G. L., & Savelsbergh, M. W. (1999). Lifted flow cover inequalities for mixed 0-1 integer programs.
11646 * Mathematical Programming, 85(3), 439-467.
11647 *
11648 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
11649 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
11650 *
11651 * @pre This method can be called if @p scip is in one of the following stages:
11652 * - \ref SCIP_STAGE_SOLVING
11653 *
11654 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
11655 */
11657 SCIP* scip, /**< SCIP data structure */
11658 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
11659 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
11660 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
11661 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
11662 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
11663 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
11664 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
11665 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
11666 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
11667 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
11668 int* cutrank, /**< pointer to return rank of generated cut */
11669 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
11670 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
11671 )
11672{
11673 SNF_RELAXATION snf;
11674 SCIP_Bool localbdsused;
11675 SCIP_Real lambda;
11676 SCIP_Real* tmpcoefs;
11677 SCIP_Real tmprhs = 0.0;
11678 SCIP_Bool tmpislocal;
11679 int* tmpinds;
11680 int tmpnnz;
11681 int* transvarflowcoverstatus;
11682 int nvars;
11683 int nflowcovervars;
11684 int nnonflowcovervars;
11685 int i;
11686
11688
11689 *success = FALSE;
11690
11691 /* get data structures */
11692 SCIP_CALL( SCIPallocBufferArray(scip, &transvarflowcoverstatus, nvars) );
11694
11695 SCIPdebug( printCutQuad(scip, sol, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, FALSE, aggrrow->local) );
11696
11697 SCIP_CALL( constructSNFRelaxation(scip, sol, boundswitch, allowlocal, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, &snf, success, &localbdsused) );
11698
11699 if( ! *success )
11700 {
11701 goto TERMINATE;
11702 }
11703
11704 tmpislocal = aggrrow->local || localbdsused;
11705
11706 /* initialize lambda because gcc issues a stupid warning */
11707 lambda = 0.0;
11708 SCIP_CALL( getFlowCover(scip, &snf, &nflowcovervars, &nnonflowcovervars, transvarflowcoverstatus, &lambda, success) );
11709
11710 if( ! *success )
11711 {
11712 goto TERMINATE;
11713 }
11714
11717
11718 SCIP_CALL( generateLiftedFlowCoverCut(scip, &snf, aggrrow, transvarflowcoverstatus, lambda, tmpcoefs, &tmprhs, tmpinds, &tmpnnz, success) );
11719 SCIPdebugMsg(scip, "computed flowcover_%lli_%i:\n", SCIPgetNLPs(scip), SCIPgetNCuts(scip));
11720
11721 /* if success is FALSE generateLiftedFlowCoverCut wont have touched the tmpcoefs array so we dont need to clean it then */
11722 if( *success )
11723 {
11724 if( postprocess )
11725 {
11726 SCIP_CALL( postprocessCut(scip, tmpislocal, tmpinds, tmpcoefs, &tmpnnz, &tmprhs, success) );
11727 }
11728 else
11729 {
11730 SCIP_Real QUAD(rhs);
11731
11732 QUAD_ASSIGN(rhs, tmprhs);
11733 *success = ! removeZeros(scip, SCIPsumepsilon(scip), tmpislocal, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz);
11734 tmprhs = QUAD_TO_DBL(rhs);
11735 }
11736
11737 if( *success )
11738 {
11739 /* only return cut if it improves upon the input efficacy threshold */
11740 if( cutefficacy != NULL )
11741 {
11742 /* calculate efficacy from dense storage */
11743 SCIP_Real efficacy = calcEfficacyDenseStorage(scip, sol, tmpcoefs, tmprhs, tmpinds, tmpnnz);
11744
11745 if( SCIPisLT(scip, *cutefficacy, efficacy) )
11746 *cutefficacy = efficacy;
11747 else
11748 *success = FALSE;
11749 }
11750
11751 /* copy cut data to output if successful */
11752 if( *success )
11753 {
11754 if( cutrank != NULL )
11755 *cutrank = aggrrow->rank + 1;
11756 if( cutislocal != NULL )
11757 *cutislocal = tmpislocal;
11758
11759 for( i = 0; i < tmpnnz; ++i )
11760 {
11761 int j = tmpinds[i];
11762
11763 cutinds[i] = j;
11764 cutcoefs[i] = tmpcoefs[j];
11765 }
11766
11767 *cutnnz = tmpnnz;
11768 *cutrhs = tmprhs;
11769 }
11770 }
11771
11772 /* clean buffer array */
11773 for( i = 0; i < tmpnnz; ++i )
11774 {
11775 int j = tmpinds[i];
11776 assert(tmpcoefs[j] != 0.0);
11777 tmpcoefs[j] = 0.0;
11778 }
11779 }
11780
11781 SCIPfreeBufferArray(scip, &tmpinds);
11782 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
11783
11784 TERMINATE:
11786 SCIPfreeBufferArray(scip, &transvarflowcoverstatus);
11787
11788 return SCIP_OKAY;
11789}
11790
11791/* =========================================== knapsack cover =========================================== */
11792
11793/** Relax the row to a possibly fractional knapsack row containing no integer or continuous variables
11794 * and only having positive coefficients for binary variables. General integer and continuous variables
11795 * are complemented with variable or simple bounds such that their coefficient becomes positive and then
11796 * it is relaxed to zero.
11797 * All remaining binary variables are complemented with simple upper or lower bounds such that their
11798 * coefficient becomes positive.
11799 */
11800static
11802 SCIP* scip, /**< SCIP data structure */
11803 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
11804 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
11805 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
11806 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
11807 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
11808 int* nnz, /**< number of non-zeros in cut */
11809 int* varsign, /**< stores the sign of the transformed variable in summation */
11810 int* boundtype, /**< stores the bound used for transformed variable:
11811 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
11812 SCIP_Bool* localbdsused, /**< pointer to store whether local bounds were used in transformation */
11813 SCIP_Bool* success /**< stores whether the row could successfully be transformed into a knapsack constraint.
11814 * Returns FALSE in case a continuous or general integer variable is unbounded in the
11815 * required direction. */
11816 )
11817{
11818 SCIP_Real* bestbds;
11819 int i;
11820 int aggrrowbinstart;
11821 int firstnonbinvar;
11822 SCIP_VAR** vars;
11823
11824 assert(varsign != NULL);
11825 assert(boundtype != NULL);
11826 assert(success != NULL);
11827 assert(localbdsused != NULL);
11828
11829 *success = FALSE;
11830
11831 /* allocate temporary memory to store best bounds and bound types */
11832 SCIP_CALL( SCIPallocBufferArray(scip, &bestbds, 2*(*nnz)) );
11833
11834 /* start with continuous variables, because using variable bounds can affect the untransformed binary
11835 * variables, and these changes have to be incorporated in the transformation of the binary variables
11836 * (binary variables have the smallest problem indices!)
11837 */
11838 SCIPsortDownInt(cutinds, *nnz);
11839
11841 firstnonbinvar = SCIPgetNBinVars(scip);
11842
11843 /* determine best bounds for the continuous and general integer variables such that they will have
11844 * a positive coefficient in the transformation */
11845 for( i = 0; i < *nnz && cutinds[i] >= firstnonbinvar; ++i )
11846 {
11847 SCIP_Real QUAD(coef);
11848 int v = cutinds[i];
11849
11850 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
11851
11852 if( QUAD_TO_DBL(coef) > 0.0 )
11853 {
11854 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable
11855 * so that it will have a positive coefficient */
11856 SCIP_CALL( findBestLb(scip, vars[v], sol, SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ? 1 : 0, allowlocal, bestbds + i, boundtype + i) );
11857
11858 /* cannot transform into knapsack */
11859 if( SCIPisInfinity(scip, -bestbds[i]) )
11860 goto TERMINATE;
11861
11862 varsign[i] = +1;
11863 }
11864 else if( QUAD_TO_DBL(coef) < 0.0 )
11865 {
11866 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable
11867 * so that it will have a positive coefficient */
11868 SCIP_CALL( findBestUb(scip, vars[v], sol, SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ? 1 : 0, allowlocal, bestbds + i, boundtype + i) );
11869
11870 /* cannot transform into knapsack */
11871 if( SCIPisInfinity(scip, bestbds[i]) )
11872 goto TERMINATE;
11873
11874 varsign[i] = -1;
11875 }
11876 }
11877
11878 /* remember start of integer variables in the aggrrow */
11879 aggrrowbinstart = i;
11880
11881 /* perform bound substitution for continuous variables */
11882 for( i = 0; i < aggrrowbinstart; ++i )
11883 {
11884 SCIP_Real QUAD(coef);
11885 int v = cutinds[i];
11886
11887 performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestbds[i], v, localbdsused);
11888
11889 /* relax non-binary coefficient to zero after bound substitution */
11890 QUAD_ASSIGN(coef, 0.0);
11891 QUAD_ARRAY_STORE(cutcoefs, v, coef);
11892 }
11893
11894 assert(i == aggrrowbinstart);
11895
11896 /* remove non-binary variables because their coefficients have been set to zero after bound substitution */
11897 if( aggrrowbinstart != 0 )
11898 {
11899 *nnz -= aggrrowbinstart;
11900 BMSmoveMemoryArray(cutinds, cutinds + aggrrowbinstart, *nnz);
11901 }
11902 i = 0;
11903
11904 /* after doing bound substitution of non-binary vars, some coefficients of binary vars might have changed, so here we
11905 * remove the ones that became 0 if any; also, we need that all remaining binary vars have positive coefficients,
11906 * thus we perform bound substitution with simple bounds (i.e. complementing) to achieve this.
11907 */
11908 while( i < *nnz )
11909 {
11910 SCIP_Real QUAD(coef);
11911 SCIP_Real bestlb;
11912 SCIP_Real bestub;
11913 SCIP_Bool setzero;
11914 int v = cutinds[i];
11915
11917
11918 assert(v < firstnonbinvar);
11919 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
11920
11921 /* due to variable bound usage for bound substitution of continuous variables cancellation may have occurred */
11922 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
11923 {
11924 /* do not increase i, since last element is copied to the i-th position */
11925 setzero = TRUE;
11926 }
11927 else
11928 {
11929 /* perform bound substitution */
11930 if( QUAD_TO_DBL(coef) < 0.0 )
11931 {
11932 SCIP_CALL( findBestUb(scip, vars[v], sol, 0, allowlocal, &bestub, boundtype + i) );
11933
11934 if( SCIPisZero(scip, bestub) )
11935 {
11936 /* binary variable is fixed to zero */
11937 setzero = TRUE;
11938 *localbdsused = *localbdsused || (boundtype[i] == -2);
11939 }
11940 else
11941 {
11942 varsign[i] = -1;
11943
11944 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestub, v, localbdsused);
11945 QUAD_ARRAY_STORE(cutcoefs, v, -coef);
11946 setzero = FALSE;
11947 }
11948 }
11949 else
11950 {
11951 SCIP_CALL( findBestLb(scip, vars[v], sol, 0, allowlocal, &bestlb, boundtype + i) );
11952
11953 if( !SCIPisZero(scip, bestlb) )
11954 {
11955 /* binary variable is fixed to one */
11956 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlb, v, localbdsused);
11957 setzero = TRUE;
11958 }
11959 else
11960 {
11961 varsign[i] = +1;
11962 setzero = FALSE;
11963 }
11964 }
11965
11966 assert(boundtype[i] == -1 || boundtype[i] == -2);
11967 }
11968
11969 /* increase i or remove zero coefficient (i.e. var with 0 coef) by shifting last nonzero to current position */
11970 if( setzero )
11971 {
11972 QUAD_ASSIGN(coef, 0.0);
11973 QUAD_ARRAY_STORE(cutcoefs, v, coef);
11974 --(*nnz);
11975 cutinds[i] = cutinds[*nnz];
11976 }
11977 else
11978 ++i;
11979 }
11980
11981 /* relax rhs to zero if it is close to but slightly below zero */
11982 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
11983 QUAD_ASSIGN(*cutrhs, 0.0);
11984
11985 *success = TRUE;
11986 TERMINATE:
11987 /*free temporary memory */
11988 SCIPfreeBufferArray(scip, &bestbds);
11989
11990 return SCIP_OKAY;
11991}
11992
11993/** determines the initial cover for the given (fractional) knapsack row */
11994static
11996 SCIP* scip, /**< SCIP datastructure */
11997 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
11998 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
11999 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
12000 SCIP_Real cutrhs, /**< pointer to the right hand side of the cut */
12001 int cutnnz, /**< pointer to the number of non-zeros in the cut */
12002 int* varsign, /**< sign of coefficients for each nonzero in the row be transformation */
12003 int* coverstatus, /**< array to return the coverstatus for each variable in the knapsack row */
12004 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
12005 SCIP_Real* covervals, /**< coefficient value of each variable in the cover */
12006 int* coversize, /**< pointer to return number of variables in the cover;
12007 * matches the length of the associated arrays */
12008 QUAD(SCIP_Real* coverweight) /**< pointer to return the weight of the cover;
12009 * the weight is the sum of the coefficient values of variables in the cover */
12010 )
12011{
12012 SCIP_VAR** vars;
12013 int k;
12014 int j;
12015 QUAD_ASSIGN(*coverweight, 0);
12016 *coversize = 0;
12017 j = cutnnz-1;
12019
12020 for( k = 0; k < cutnnz; ++k )
12021 {
12022 SCIP_Real solval;
12023 int v = cutinds[k];
12024 SCIP_Real QUAD(coef);
12025 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
12026
12027 solval = SCIPgetSolVal(scip, sol, vars[v]);
12028 if( varsign[k] == -1 )
12029 solval = 1 - solval;
12030
12031 if( SCIPisFeasEQ(scip, solval, 1.0) )
12032 {
12033 /* every variable with solution value 1 is forced into the cover */
12034 coverpos[*coversize] = k;
12035 covervals[*coversize] = QUAD_TO_DBL(coef);
12036 coverstatus[k] = 1;
12037 *coversize += 1;
12038 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
12039 }
12040 else
12041 {
12042 coverpos[j] = k;
12043 covervals[j] = solval * QUAD_TO_DBL(coef);
12044 coverstatus[k] = 0;
12045 j -= 1;
12046 }
12047 }
12048
12049 /* Use these two arrays to sort the variables by decreasing contribution
12050 * and pick them greedily in the while loop below until they are a cover.
12051 * Since the cover does not need to be minimal we do not need to remove any of the
12052 * variables with a high activity contribution even if they are not necessary after
12053 * picking the last variable.
12054 */
12055 SCIPsortDownRealInt(covervals + (*coversize), coverpos + (*coversize), cutnnz - (*coversize));
12056
12057 /* overwrite covervals with the coefficients of the variables in the cover
12058 * as we need to sort decreasingly by those again for the lifting
12059 */
12060 while( *coversize < cutnnz &&
12061 SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) )
12062 {
12063 int v;
12064 SCIP_Real QUAD(coef);
12065 k = coverpos[*coversize];
12066 v = cutinds[k];
12067 coverstatus[k] = 1;
12068 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
12069 covervals[*coversize] = QUAD_TO_DBL(coef);
12070 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
12071 *coversize += 1;
12072 }
12073
12074 /* there is no cover */
12075 if( SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) || *coversize == 0 )
12076 return FALSE;
12077
12078 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(*coverweight), cutrhs);
12079 assert(*coversize > 0);
12080
12081 return TRUE;
12082}
12083
12084/** prepares the data needed to evaluate the lifting function */
12085static
12087 SCIP* scip, /**< SCIP datastructure */
12088 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
12089 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
12090 QUAD(SCIP_Real cutrhs), /**< pointer to the right hand side of the cut */
12091 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
12092 int coversize, /**< number of variables in the cover */
12093 QUAD(SCIP_Real coverweight), /**< weight of cover */
12094 SCIP_Real* covervals, /**< coefficient value of each variable in the cover;
12095 * on output stores the running sum of S^-(*) values */
12096 int* coverstatus, /**< coverstatus for each variable in the cover. After calling this function
12097 * variables in C^- will have the value -1, variables in C^+ the value 1,
12098 * and all variables outside the cover keep the value 0. */
12099 QUAD(SCIP_Real* abar), /**< pointer to store the reciprocal value of \bar{a} */
12100 int* cplussize /**< pointer to store the size of C^+ */
12101 )
12102{
12103 int k;
12104 SCIP_Real QUAD(tmp);
12105 SCIP_Real QUAD(sigma);
12106
12107 /* Now compute \bar{a}, the unique rational number such that for the cover C it holds that
12108 * b = \sum_{a_i \in C} \min(\bar{a}, a_i).
12109 * For that we need to sort by decreasing coefficients of the variables in the cover.
12110 * After the sorting the covervals array is free to be reused.
12111 */
12112 SCIPsortDownRealInt(covervals, coverpos, coversize);
12113
12114 /* Now follows Algorithm 1 in the paper to compute \bar{a} */
12115
12116 /* set \bar{a} = l_1 */
12117 QUAD_ARRAY_LOAD(*abar, cutcoefs, cutinds[coverpos[0]]);
12118 SCIPquadprecSumQQ(sigma, coverweight, -cutrhs);
12119
12120 for( k = 1; k < coversize; ++k )
12121 {
12122 SCIP_Real QUAD(lkplus1);
12123 SCIP_Real QUAD(kdelta);
12124
12125 /* load next coefficient l_{k+1} in sorted order of cover */
12126 QUAD_ARRAY_LOAD(lkplus1, cutcoefs, cutinds[coverpos[k]]);
12127
12128 /* Let \delta = \bar{a} - l_{k+1} and compute k * \delta */
12129 SCIPquadprecSumQQ(kdelta, *abar, -lkplus1);
12130 SCIPquadprecProdQD(kdelta, kdelta, k);
12131
12132 /* Set tmp = k * \delta - \sigma to check condition k * \delta < \sigma by tmp < 0 */
12133 SCIPquadprecSumQQ(tmp, kdelta, -sigma);
12134 if( QUAD_TO_DBL(tmp) < 0.0 )
12135 {
12136 /* Set \bar{a} = l_{k+1} and \sigma = \sigma - k*\delta */
12137 QUAD_ASSIGN_Q(*abar, lkplus1);
12138 SCIPquadprecSumQQ(sigma, sigma, -kdelta);
12139 }
12140 else
12141 {
12142 /* Set \bar{a} = \bar{a} - \sigma / k and \sigma = 0; break; */
12143 SCIP_Real minusoneoverk = -1.0 / k;
12144 SCIPquadprecProdQD(sigma, sigma, minusoneoverk);
12145 SCIPquadprecSumQQ(*abar, *abar, sigma);
12146 QUAD_ASSIGN(sigma, 0.0);
12147 break;
12148 }
12149 }
12150
12151 if( QUAD_TO_DBL(sigma) > 0.0 )
12152 {
12153 SCIP_Real oneoverc = 1.0 / coversize;
12154 SCIPquadprecProdQD(*abar, cutrhs, oneoverc);
12155 }
12156
12157 /* now we partition C into C^+ and C^-, where C^+ are all the elements of C whose weight is strictly larger than
12158 * \bar{a} and C^- the rest. If a_i are the weights of the elements in C, let a_i^- = min(a_i, \bar{a}) We also
12159 * compute S^-(h) = sum of the h largest a_i^- and store S^-(h+1) in in covervals[h], for k = 0, ..., coversize - 1
12160 * (S^-(0) = 0 so it doesn't need to be stored; we use S to compute the lifted cut, see below)
12161 * we remember which elements of C^- in coverstatus, so that element in C^+ have coverstatus 1 and
12162 * elements in C^- have coverstatus -1 (elements not in C have coverstatus 0)
12163 */
12164 QUAD_ASSIGN(tmp, 0.0);
12165 *cplussize = 0;
12166 for( k = 0; k < coversize; ++k )
12167 {
12168 SCIP_Real QUAD(coef);
12169 SCIP_Real QUAD(coefminusabar);
12170
12171 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[coverpos[k]]);
12172 SCIPquadprecSumQQ(coefminusabar, coef, -*abar);
12173 if( QUAD_TO_DBL(coefminusabar) > 0.0 )
12174 {
12175 /* coefficient is in C^+ because it is greater than \bar{a} and contributes only \bar{a} to the sum */
12176 SCIPquadprecSumQQ(tmp, tmp, *abar);
12177
12178 /* rather be on the safe side in numerical corner cases and relax the coefficient to exactly \bar{a}.
12179 * In that case the coefficient is not treated as in C^+ but as being <= \bar{a} and therefore in C^-.
12180 */
12181 if( QUAD_TO_DBL(coefminusabar) > SCIPfeastol(scip) )
12182 ++(*cplussize);
12183 else
12184 coverstatus[coverpos[k]] = -1;
12185 }
12186 else
12187 {
12188 /* coefficient is in C^- because it is smaller or equal to \bar{a} */
12189 coverstatus[coverpos[k]] = -1;
12190 SCIPquadprecSumQQ(tmp, tmp, coef);
12191 }
12192 covervals[k] = QUAD_TO_DBL(tmp);
12193 SCIPdebugMsg(scip, "S^-(%d) = %g\n", k + 1, covervals[k]);
12194 }
12195
12196 /* set abar to its reciprocal for faster computation of the lifting coefficients */
12197 SCIPquadprecDivDQ(*abar, 1, *abar);
12198}
12199
12200/** evaluate the lifting function based on the given values */
12201static
12203 SCIP* scip, /**< SCIP datastructure */
12204 QUAD(SCIP_Real x), /**< value to evaluate the lifting function at */
12205 QUAD(SCIP_Real abar), /**< the reciprocal value of \bar{a} */
12206 SCIP_Real* covervals, /**< the running sum of S^-(*) values */
12207 int coversize, /**< the size of the cover */
12208 int cplussize, /**< the size of C^+ */
12209 SCIP_Real* scale /**< pointer to update the scale to integrality when a fractional value is returned */
12210 )
12211{
12212 SCIP_Real QUAD(tmp);
12213 SCIP_Real QUAD(hfrac);
12214 SCIP_Real cutcoef;
12215 SCIP_Real hreal;
12216 int h;
12217
12218 /* the lifted value is at least the coeficient (a_k) divided by \bar{a} because the largest value
12219 * contributed to the running sum stored in C is \bar{a}
12220 * therefore we start the search for the correct h at floor(a_k / \bar{a})
12221 */
12222
12223 SCIPdebugMsg(scip, "coef is %g, coversize is %d\n", QUAD_TO_DBL(x), coversize );
12224
12225 SCIPquadprecProdQQ(hfrac, x, abar);
12226
12227 /* if the coefficient is below \bar{a}, i.e. a / \bar{a} < 1 then g(a_k) = 0, otherwise g(a_k) > 0 */
12228 if( QUAD_TO_DBL(hfrac) < 1 )
12229 return 0.0;
12230
12231 /* we perform h = MIN(h, coversize) in floating-point first because on some instances h was seen to exceed the range
12232 * of int */
12233 hreal = SCIPfloor(scip, QUAD_TO_DBL(hfrac));
12234 if( hreal > (SCIP_Real)coversize )
12235 h = coversize;
12236 else
12237 h = (int)hreal;
12238
12239 SCIPquadprecSumQD(hfrac, hfrac, -h);
12240
12241 assert(h > 0);
12242 if( h < cplussize && ABS(QUAD_TO_DBL(hfrac)) <= QUAD_EPSILON )
12243 {
12244 /* cutcoef can be increased by 0.5 because it is a multiple of \bar{a}
12245 * (This is the first non-dominated lifting function presented in the paper)
12246 */
12247 cutcoef = 0.5;
12248 *scale = 2.0;
12249 }
12250 else
12251 cutcoef = 0.0;
12252
12253 /* decrease by one to make sure rounding errors or coefficients that are larger than the right hand side by themselves
12254 * did not push h too far */
12255 h--;
12256
12257 /* now increase coefficient to its lifted value based on its size relative to the S^- values.
12258 * The coefficient a_i is lifted to the unique integer h such that S^-(h) < a_i <= S^-(h+1).
12259 * (todo: variables that have a coefficient above the right hand side can get an arbitrarily large coefficient but can
12260 * also be trivially fixed using the base row. Currently they get the coefficient |C| which is 1 above the right hand
12261 * side in the cover cut so that they can still be trivially fixed by propagating the cover cut.
12262 * We do not want to apply fixings here though because the LP should stay flushed during separation.
12263 * Possibly add a parameter to return additional fixings to the caller of the SCIPcalc*() functions in here
12264 * and the caller can add them as cuts to the sepastore or we add them to the sepastore here?)
12265 */
12266 while( h < coversize )
12267 {
12268 SCIPquadprecSumQD(tmp, x, -covervals[h]); /* recall: covervals[h] = S^-(h+1) */
12269 /* compare with standard epsilon tolerance since computation involves abar, which is computed like an activity */
12270 if( !SCIPisPositive(scip, QUAD_TO_DBL(tmp)) )
12271 break;
12272
12273 ++h;
12274 }
12275
12276 cutcoef += h;
12277
12278 SCIPdebugMsg(scip, "x is %g, coversize is %d, h is %d\n", QUAD_TO_DBL(x), coversize, h );
12279 /* the lifted coefficient is h increased possibly by 0.5 for the case checked above */
12280 SCIPdebugMsg(scip, "lifted coef %g < %g <= %g to %g\n", h == 0 ? 0 : covervals[h-1], QUAD_TO_DBL(x),
12281 covervals[h], cutcoef);
12282
12283 return cutcoef;
12284}
12285
12286/** calculates a lifted knapsack cover cut out of the weighted sum of LP rows given by an aggregation row; the
12287 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
12288 * participate in the cut.
12289 * For further details we refer to:
12290 *
12291 * Letchford, A. N., & Souli, G. (2019). On lifted cover inequalities: A new lifting procedure with unusual properties.
12292 * Operations Research Letters, 47(2), 83-87.
12293 *
12294 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
12295 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
12296 *
12297 * @pre This method can be called if @p scip is in one of the following stages:
12298 * - \ref SCIP_STAGE_SOLVING
12299 *
12300 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
12301 */
12303 SCIP* scip, /**< SCIP data structure */
12304 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
12305 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
12306 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
12307 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
12308 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
12309 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
12310 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
12311 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
12312 int* cutrank, /**< pointer to return rank of generated cut */
12313 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
12314 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
12315 )
12316{
12317 int* varsign;
12318 int* boundtype;
12319 int* coverstatus;
12320 int* coverpos;
12321 int* tmpinds;
12322 SCIP_Real* tmpcoefs;
12323 SCIP_Real* covervals;
12324 SCIP_Real QUAD(rhs);
12325 SCIP_Real QUAD(coverweight);
12326 SCIP_Real QUAD(abar);
12327 SCIP_Bool transformed;
12328 SCIP_Bool local;
12329 SCIP_Real efficacy;
12330 SCIP_Real scale;
12331 int k;
12332 int nvars;
12333 int coversize;
12334 int cplussize;
12335 int nnz;
12336
12337 assert(scip != NULL);
12338 assert(aggrrow != NULL);
12339 assert(cutcoefs != NULL);
12340 assert(cutrhs != NULL);
12341 assert(cutinds != NULL);
12342 assert(cutnnz != NULL);
12343 assert(cutefficacy != NULL);
12344 assert(cutislocal != NULL);
12345 assert(success != NULL);
12346
12347 *success = FALSE;
12348
12349 if( aggrrow->nnz == 0 )
12350 return SCIP_OKAY;
12351
12352 for( k = 0; k < aggrrow->nrows; ++k )
12353 {
12354 /* cannot handle negative slack variables */
12355 if( aggrrow->rowweights[k] * aggrrow->slacksign[k] < 0 )
12356 return SCIP_OKAY;
12357 }
12358
12359 /* allocate temporary memory */
12362 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
12363 SCIP_CALL( SCIPallocBufferArray(scip, &coverstatus, nvars) );
12364 SCIP_CALL( SCIPallocBufferArray(scip, &covervals, nvars) );
12365 SCIP_CALL( SCIPallocBufferArray(scip, &coverpos, nvars) );
12368
12369 /* initialize cut with aggregation */
12370 nnz = aggrrow->nnz;
12371 QUAD_ASSIGN_Q(rhs, aggrrow->rhs);
12372
12373 BMScopyMemoryArray(tmpinds, aggrrow->inds, nnz);
12374
12375 for( k = 0; k < nnz; ++k )
12376 {
12377 SCIP_Real QUAD(coef);
12378 int j = tmpinds[k];
12379
12380 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
12381
12382 QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
12383 assert(QUAD_HI(coef) != 0.0);
12384
12385 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
12386 }
12387 SCIPdebugMsg(scip, "Computing lifted knapsack cover for ");
12388 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
12389
12390 /* Transform aggregated row into a (fractional, i.e. with possibly fractional weights) knapsack constraint.
12391 * Uses simple or variable lower or upper bounds to relax out continuous and general integers
12392 * so that only binary variables remain and complements those such that they have a positive coefficient.
12393 */
12394 local = aggrrow->local;
12396 tmpcoefs, QUAD(&rhs), tmpinds, &nnz, varsign, boundtype, &local, &transformed) );
12397
12398 assert(allowlocal || !local);
12399
12400 if( !transformed )
12401 goto TERMINATE;
12402
12403 SCIPdebugMsg(scip, "Transformed knapsack relaxation ");
12404 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
12405
12406 if( !computeInitialKnapsackCover(scip, sol, tmpcoefs, tmpinds, QUAD_TO_DBL(rhs), nnz, varsign, coverstatus,
12407 coverpos, covervals, &coversize, QUAD(&coverweight)) )
12408 goto TERMINATE;
12409
12410 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(coverweight), QUAD_TO_DBL(rhs));
12411 assert(coversize > 0);
12412
12413 /* by default do not scale the cut */
12414 scale = 1.0;
12415
12416 if( coversize == 1 )
12417 {
12418 SCIP_Real QUAD(tmp);
12419 /* cover is trivial, return the fixing as cut */
12420 QUAD_ASSIGN(tmp, 0.0);
12421 for( k = 0; k < nnz; ++k )
12422 {
12423 if( coverstatus[k] == 0 )
12424 {
12425 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
12426 }
12427 else
12428 {
12429 tmpinds[0] = tmpinds[k];
12430 varsign[0] = varsign[k];
12431 }
12432 }
12433
12434 nnz = 1;
12435 if( varsign[0] == -1 )
12436 {
12437 QUAD_ASSIGN(rhs, -1.0);
12438 QUAD_ASSIGN(tmp, -1.0);
12439 }
12440 else
12441 {
12442 QUAD_ASSIGN(rhs, 0.0);
12443 QUAD_ASSIGN(tmp, 1.0);
12444 }
12445
12446 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[0], tmp);
12447 }
12448 else
12449 {
12450 SCIP_Real QUAD(tmp);
12451
12452 /* compute lifted cover inequality:
12453 * sum_{i \in C^-) x_i + sum_{i \in N \ C^-) g(a_i) x_i <= c - 1
12454 * where g(z) is equal to
12455 * - 0 if z is 0 (irrelevant as there shouldn't be element with weight 0 in the knapsack)
12456 * - h + 1/2 if z = k * \bar{a} for some integer k \in [1, |C^+| - 1] and S^-(h) < z <= S^-(h+1) for some h = 0, ..., coversize -1
12457 * - h if S^-(h) < z <= S^-(h+1) for some h = 0, ..., coversize -1
12458 * the function S^- is defined above. Note that S^-(0) = 0
12459 * we store the cut coefficients in tmpcoef
12460 */
12461
12462 SCIPdebugMsg(scip, "call prepareLiftingData: \n");
12463 /* prepare data required to evaluate lifting function */
12464 prepareLiftingData(scip, tmpcoefs, tmpinds, QUAD(rhs), coverpos, coversize,
12465 QUAD(coverweight), covervals, coverstatus, QUAD(&abar), &cplussize);
12466
12467 /* compute lifted cover inequality */
12468 QUAD_ASSIGN(rhs, (coversize - 1));
12469 for( k = 0; k < nnz; )
12470 {
12471 SCIP_Real cutcoef;
12472 if( coverstatus[k] == -1 )
12473 { /* variables in C^- get the coefficients 1 */
12474 cutcoef = 1.0;
12475 }
12476 else
12477 { /* variables is either in C^+ or not in the cover and its coefficient value is computed with the lifing function */
12478 SCIP_Real QUAD(coef);
12479
12480 SCIPdebugMsg(scip, "load QUAD(coef) from tmpcoefs[tmpinds[k] = %d]\n",tmpinds[k]);
12481 QUAD_ARRAY_LOAD(coef, tmpcoefs, tmpinds[k]);
12482
12483 SCIPdebugMsg(scip, "coef is QUAD_HI=%g, QUAD_LO=%g, QUAD_TO_DBL = %g\n",QUAD_HI(coef), QUAD_LO(coef), QUAD_TO_DBL(coef));
12484
12485 SCIPdebugMsg(scip, "call evaluateLiftingFunctionKnapsack:\n");
12486 cutcoef = evaluateLiftingFunctionKnapsack(scip, QUAD(coef), QUAD(abar), covervals, coversize, cplussize, &scale);
12487
12488 /* if the coefficient value is zero then remove the nonzero entry and continue */
12489 if( cutcoef == 0.0 )
12490 {
12491 QUAD_ASSIGN(tmp, 0.0);
12492 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
12493 --nnz;
12494 coverstatus[k] = coverstatus[nnz];
12495 tmpinds[k] = tmpinds[nnz];
12496 varsign[k] = varsign[nnz];
12497 continue;
12498 }
12499 }
12500
12501 /* directly undo the complementation before storing back the coefficient */
12502 if( varsign[k] == -1 )
12503 {
12504 /* variable was complemented so we have cutcoef * (1-x) = cutcoef - cutcoef * x.Thus we need to adjust the rhs
12505 * to rhs - cutcoef and flip the sign of cutcoef */
12506 cutcoef = -cutcoef;
12507 SCIPquadprecSumQD(rhs, rhs, cutcoef);
12508 }
12509
12510 QUAD_ASSIGN(tmp, cutcoef);
12511 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
12512
12513 ++k;
12514 }
12515 }
12516
12517 /* calculate the efficacy of the computed cut and store the success flag if the efficacy exceeds the
12518 * one stored in the cutefficacy variable by the caller
12519 */
12520 efficacy = calcEfficacyDenseStorageQuad(scip, sol, tmpcoefs, QUAD_TO_DBL(rhs), tmpinds, nnz);
12521 *success = SCIPisGT(scip, efficacy, *cutefficacy);
12522
12523 SCIPdebugMsg(scip, "FINAL LCI:");
12524 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
12525
12526 if( *success )
12527 {
12528 /* return the cut into the given arrays/pointers */
12529 *cutislocal = local;
12530 *cutrhs = scale * QUAD_TO_DBL(rhs);
12531 *cutnnz = nnz;
12532
12533 /* store cut in given array in sparse representation and clean buffer array */
12534 for( k = 0; k < nnz; ++k )
12535 {
12536 SCIP_Real QUAD(coef);
12537 int j = tmpinds[k];
12538
12539 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
12540 assert(QUAD_HI(coef) != 0.0);
12541
12542 cutcoefs[k] = scale * QUAD_TO_DBL(coef);
12543 cutinds[k] = j;
12544 QUAD_ASSIGN(coef, 0.0);
12545 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
12546 }
12547
12548 assert( cutefficacy != NULL );
12549 /* calculate efficacy again to make sure it matches the coefficients after they where rounded to double values
12550 * and after the cleanup and postprocessing step was applied. */
12551 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, nnz);
12552
12553 if( cutrank != NULL )
12554 *cutrank = aggrrow->rank + 1;
12555 }
12556
12557 TERMINATE:
12558
12559 /* if we aborted early the tmpcoefs array needs to be cleaned */
12560 if( !(*success) )
12561 {
12562 SCIP_Real QUAD(tmp);
12563 QUAD_ASSIGN(tmp, 0.0);
12564
12565 for( k = 0; k < nnz; ++k )
12566 {
12567 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
12568 }
12569 }
12570#ifndef NDEBUG
12571 for( k = 0; k < QUAD_ARRAY_SIZE(nvars); ++k )
12572 {
12573 if(tmpcoefs[k] != 0.0)
12574 {
12575 SCIPdebugMsg(scip, "tmpcoefs have not been reset\n");
12576 SCIPABORT();
12577 }
12578 }
12579#endif
12580
12581 /* free temporary memory */
12582 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
12583 SCIPfreeBufferArray(scip, &tmpinds);
12584 SCIPfreeBufferArray(scip, &coverpos);
12585 SCIPfreeBufferArray(scip, &covervals);
12586 SCIPfreeBufferArray(scip, &coverstatus);
12587 SCIPfreeBufferArray(scip, &boundtype);
12588 SCIPfreeBufferArray(scip, &varsign);
12589
12590 return SCIP_OKAY;
12591}
12592
12593
12594/* =========================================== strongcg =========================================== */
12595
12596/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
12597 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
12598 *
12599 * Differs from cutsTransformMIR for continuous variables for which the lower bound must be used
12600 * when in case their coefficient is positive and the upper bound in case their coefficient is
12601 * negative. This forces all continuous variable to have a positive coefficient in the transformed
12602 * row.
12603 *
12604 * Transform variables (lb or ub):
12605 * \f[
12606 * \begin{array}{llll}
12607 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \mbox{if lb is used in transformation}\\
12608 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if ub is used in transformation}
12609 * \end{array}
12610 * \f]
12611 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
12612 *
12613 * Transform variables (vlb or vub):
12614 * \f[
12615 * \begin{array}{llll}
12616 * x^\prime_j := x_j - (bl_j\, zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \mbox{if vlb is used in transf.} \\
12617 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if vub is used in transf.}
12618 * \end{array}
12619 * \f]
12620 * move the constant terms \f$ a_j\, dl_j \f$ or \f$ a_j\, du_j \f$ to the rhs, and update the coefficient of the VLB variable:
12621 * \f[
12622 * \begin{array}{ll}
12623 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
12624 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
12625 * \end{array}
12626 * \f]
12627 */
12628static
12630 SCIP* scip, /**< SCIP datastructure */
12631 MIR_DATA* data, /**< the MIR data structure for this cut */
12632 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
12633 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
12634 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
12635 int* varsign, /**< stores the sign of the transformed variable in summation */
12636 int* boundtype, /**< stores the bound used for transformed variable:
12637 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
12638 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
12639 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
12640 )
12641{
12642 SCIP_Real* bestlbs;
12643 SCIP_Real* bestubs;
12644 int* bestlbtypes;
12645 int* bestubtypes;
12646 SCIP_BOUNDTYPE* selectedbounds;
12647 int totalnnz;
12648 int s;
12649 int i;
12650
12651 assert(data != NULL);
12652 assert(varsign != NULL);
12653 assert(boundtype != NULL);
12654 assert(freevariable != NULL);
12655 assert(localbdsused != NULL);
12656
12657 totalnnz = data->totalnnz;
12658
12659 *freevariable = FALSE;
12660 *localbdsused = FALSE;
12661
12662 /* allocate temporary memory to store best bounds and bound types */
12663 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*totalnnz) );
12664 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*totalnnz) );
12665 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*totalnnz) );
12666 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*totalnnz) );
12667 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*totalnnz) );
12668
12669 /* transform the cut, one variable section at a time */
12670 for( s = 0; s < NSECTIONS; ++s )
12671 {
12672 int* indices = data->secindices[s];
12673 int cutindsstart = data->ncutinds;
12674 int usevbds = data->usevbds[s];
12675
12676 i = 0;
12677 /* Iterate over all nonzeros in the section */
12678 while( i < data->secnnz[s] )
12679 {
12680 SCIP_Real QUAD(coef);
12681 int v = indices[i];
12682
12683 /* due to variable bound usage, cancellation may have occurred */
12684 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
12685 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
12686 {
12687 QUAD_ASSIGN(coef, 0.0);
12688 QUAD_ARRAY_STORE(data->cutcoefs, v, coef);
12689 --data->secnnz[s];
12690 --data->totalnnz;
12691 indices[i] = indices[data->secnnz[s]];
12692 /* do not increase the index */
12693 continue;
12694 }
12695
12696 int cutindex = data->ncutinds;
12697 /* For continuous variables, we must choose the bound substitution so that they become positive in the cut */
12698 if( !data->isenfint[s] && !data->isimplint[s] )
12699 {
12700 if( QUAD_TO_DBL(coef) > 0.0 )
12701 {
12702 SCIP_Real simplelb;
12703
12704 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
12705 SCIP_CALL( findMIRBestLb(scip, data->vars[v], sol, data, usevbds, allowlocal,
12706 bestlbs + cutindex, &simplelb, bestlbtypes + cutindex) );
12707
12708 /* cannot create transformation for strongcg cut */
12709 if( SCIPisInfinity(scip, -bestlbs[cutindex]) )
12710 {
12711 *freevariable = TRUE;
12712 goto TERMINATE;
12713 }
12714
12715 varsign[cutindex] = +1;
12716 selectedbounds[cutindex] = SCIP_BOUNDTYPE_LOWER;
12717 }
12718 else
12719 {
12720 SCIP_Real simpleub;
12721
12722 assert(QUAD_TO_DBL(coef) < 0.0);
12723
12724 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
12725 SCIP_CALL( findMIRBestUb(scip, data->vars[v], sol, data, usevbds, allowlocal,
12726 bestubs + cutindex, &simpleub, bestubtypes + cutindex) );
12727
12728 /* cannot create transformation for strongcg cut */
12729 if( SCIPisInfinity(scip, bestubs[cutindex]) )
12730 {
12731 *freevariable = TRUE;
12732 goto TERMINATE;
12733 }
12734
12735 varsign[cutindex] = -1;
12736 selectedbounds[cutindex] = SCIP_BOUNDTYPE_UPPER;
12737 }
12738 }
12739 else if( data->isimplint[s] )
12740 {
12741 /* For implied integers, we still prefer to choose the bound substitution that makes them positive, but
12742 * if we cannot manage to do so it is not an error, because we can still treat them as integer variables */
12743 SCIP_Real simplelb;
12744 SCIP_Real simpleub;
12745 SCIP_Bool lowerinf;
12746 SCIP_Bool upperinf;
12747 SCIP_Bool positive;
12748
12749 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
12750 SCIP_CALL( findMIRBestLb(scip, data->vars[v], sol, data, usevbds, allowlocal,
12751 bestlbs + cutindex, &simplelb, bestlbtypes + cutindex) );
12752
12753 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
12754 SCIP_CALL( findMIRBestUb(scip, data->vars[v], sol, data, usevbds, allowlocal,
12755 bestubs + cutindex, &simpleub, bestubtypes + cutindex) );
12756
12757 lowerinf = SCIPisInfinity(scip, -bestlbs[cutindex]);
12758 upperinf = SCIPisInfinity(scip, bestubs[cutindex]);
12759 positive = QUAD_TO_DBL(coef) > 0.0;
12760
12761 if( lowerinf && upperinf )
12762 {
12763 /* we found a free variable in the row with non-zero coefficient
12764 * -> MIR row can't be transformed in standard form
12765 */
12766 *freevariable = TRUE;
12767 goto TERMINATE;
12768 }
12769
12770 /* preferably, choose bound that makes value positive */
12771 if( (positive && lowerinf) || (!positive && !upperinf) )
12772 {
12773 varsign[cutindex] = -1;
12774 selectedbounds[cutindex] = SCIP_BOUNDTYPE_UPPER;
12775 }
12776 else
12777 {
12778 varsign[cutindex] = +1;
12779 selectedbounds[cutindex] = SCIP_BOUNDTYPE_LOWER;
12780 }
12781 }
12782 else
12783 {
12784 /* For explicit integers, we have no restrictions. */
12785 SCIP_CALL( determineBestBounds(scip, data->vars[v], sol, data, boundswitch, usevbds, allowlocal, FALSE, FALSE,
12786 NULL, NULL, bestlbs + cutindex, bestubs + cutindex,
12787 bestlbtypes + cutindex, bestubtypes + cutindex, selectedbounds + cutindex, freevariable) );
12788
12789 if( *freevariable)
12790 goto TERMINATE;
12791 }
12792
12793 data->cutinds[cutindex] = v;
12794 ++data->ncutinds;
12795
12796 ++i;
12797 }
12798
12799 /* perform bound substitution for all nonzeros in the section */
12800 for( i = cutindsstart; i < data->ncutinds; ++i )
12801 {
12802 SCIP_Real bestbnd;
12803 int v = data->cutinds[i];
12804
12805 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
12806 {
12807 assert(!SCIPisInfinity(scip, -bestlbs[i]));
12808
12809 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
12810 boundtype[i] = bestlbtypes[i];
12811 varsign[i] = +1;
12812 bestbnd = bestlbs[i];
12813 }
12814 else
12815 {
12816 assert(!SCIPisInfinity(scip, bestubs[i]));
12817
12818 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
12819 boundtype[i] = bestubtypes[i];
12820 varsign[i] = -1;
12821 bestbnd = bestubs[i];
12822 }
12823
12824 doMIRBoundSubstitution(scip, data, varsign[i], boundtype[i], bestbnd, v, localbdsused);
12825 }
12826 }
12827
12828 /* relax rhs to zero if it is close to */
12829 if( QUAD_TO_DBL(data->cutrhs) < 0.0 && QUAD_TO_DBL(data->cutrhs) >= -SCIPepsilon(scip) )
12830 QUAD_ASSIGN(data->cutrhs, 0.0);
12831
12832 TERMINATE:
12833
12834 /* If we terminate early, we need to make sure all the zeros in the cut coefficient array are cancelled */
12835 if( *freevariable )
12836 {
12837 int j;
12838 int k;
12839
12840 data->ncutinds = 0;
12841 for( j = 0; j < NSECTIONS; ++j )
12842 {
12843 int* indexlist = data->secindices[j];
12844 for( k = 0; k < data->secnnz[j]; ++k )
12845 {
12846 data->cutinds[data->ncutinds] = indexlist[k];
12847 ++data->ncutinds;
12848 }
12849 }
12850 }
12851
12852 /*free temporary memory */
12853 SCIPfreeBufferArray(scip, &selectedbounds);
12854 SCIPfreeBufferArray(scip, &bestubtypes);
12855 SCIPfreeBufferArray(scip, &bestlbtypes);
12856 SCIPfreeBufferArray(scip, &bestubs);
12857 SCIPfreeBufferArray(scip, &bestlbs);
12858
12859 return SCIP_OKAY;
12860}
12861
12862/** Calculate fractionalities \f$ f_0 := b - down(b) \f$, \f$ f_j := a^\prime_j - down(a^\prime_j) \f$,
12863 * integer \f$ k \geq 1 \f$ with \f$ 1/(k + 1) \leq f_0 < 1/k \f$ \f$ (\Rightarrow k = up(1/f_0) - 1) \f$ and
12864 * integer \f$ 1 \leq p_j \leq k \f$ with \f$ f_0 + ((p_j - 1) \cdot (1 - f_0)/k) < f_j \leq f_0 + (p_j (1 - f_0)/k)\f$ \f$ (\Rightarrow p_j = up( k\,(f_j - f_0)/(1 - f_0) )) \f$
12865 * and derive strong CG cut \f$ \tilde{a} x^\prime \leq down(b) \f$
12866 * \f[
12867 * \begin{array}{rll}
12868 * integers : & \tilde{a}_j = down(a^\prime_j) &, if \qquad f_j \leq f_0 \\
12869 * & \tilde{a}_j = down(a^\prime_j) + p_j/(k + 1) &, if \qquad f_j > f_0 \\
12870 * continuous:& \tilde{a}_j = 0 &, if \qquad a^\prime_j \geq 0 \\
12871 * & \mbox{no strong CG cut found} &, if \qquad a^\prime_j < 0
12872 * \end{array}
12873 * \f]
12874 *
12875 * Transform inequality back to \f$ \hat{a}*x <= rhs \f$:
12876 *
12877 * (lb or ub):
12878 * \f[
12879 * \begin{array}{lllll}
12880 * x^\prime_j := x_j - lb_j,& x_j == x^\prime_j + lb_j,& a^\prime_j == a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation} \\
12881 * x^\prime_j := ub_j - x_j,& x_j == ub_j - x^\prime_j,& a^\prime_j == -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation}
12882 * \end{array}
12883 * \f]
12884 * \f[
12885 * and move the constant terms
12886 * \begin{array}{rl}
12887 * -\tilde{a}_j * lb_j == -\hat{a}_j * lb_j, & \mbox{or} \\
12888 * \tilde{a}_j * ub_j == -\hat{a}_j * ub_j &
12889 * \end{array}
12890 * \f]
12891 * to the rhs.
12892 *
12893 * (vlb or vub):
12894 * \f[
12895 * \begin{array}{lllll}
12896 * x^\prime_j := x_j - (bl_j * zl_j + dl_j),& x_j == x^\prime_j + (bl_j * zl_j + dl_j),& a^\prime_j == a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
12897 * x^\prime_j := (bu_j * zu_j + du_j) - x_j,& x_j == (bu_j * zu_j + du_j) - x^\prime_j,& a^\prime_j == -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
12898 * \end{array}
12899 * \f]
12900 * move the constant terms
12901 * \f[
12902 * \begin{array}{rl}
12903 * -\tilde{a}_j * dl_j == -\hat{a}_j * dl_j,& \mbox{or} \\
12904 * \tilde{a}_j * du_j == -\hat{a}_j * du_j &
12905 * \end{array}
12906 * \f]
12907 * to the rhs, and update the VB variable coefficients:
12908 * \f[
12909 * \begin{array}{ll}
12910 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j * bl_j == \hat{a}_{zl_j} - \hat{a}_j * bl_j,& \mbox{or} \\
12911 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j * bu_j == \hat{a}_{zu_j} - \hat{a}_j * bu_j &
12912 * \end{array}
12913 * \f]
12914 */
12915static
12917 SCIP* scip, /**< SCIP datastructure */
12918 MIR_DATA* data, /**< the MIR data structure for this cut */
12919 int* varsign, /**< stores the sign of the transformed variable in summation */
12920 int* boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub)*/
12921 QUAD(SCIP_Real f0), /**< fractional value of rhs */
12922 SCIP_Real k /**< factor to strengthen strongcg cut */
12923 )
12924{
12925 SCIP_Real QUAD(tmp);
12926 SCIP_Real QUAD(onedivoneminusf0);
12927 int cutindex;
12928 int s;
12929 int i;
12930
12931 assert(data != NULL);
12932 assert(boundtype != NULL);
12933 assert(varsign != NULL);
12934 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
12935
12936 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
12937 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
12938
12939 /* Loop backwards through the sections, so that the reversing of varbound substitutions does not prematurely effect
12940 * the coefficients of variables in other sections, because the section index of a variable bound must always be
12941 * higher than that of the bounded variable. */
12942 cutindex = data->ncutinds - 1;
12943 for( s = NSECTIONS - 1; s >= 0; --s )
12944 {
12945 int* indices = data->secindices[s];
12946 int nnz = data->secnnz[s];
12947 SCIP_Bool enfintegral = data->isenfint[s];
12948 SCIP_Bool implintegral = data->isimplint[s];
12949
12950 /* iterate backwards over indices in section, so we can easily shrink the section if we find zeros */
12951 for( i = nnz - 1; i >= 0 ; --i )
12952 {
12953 SCIP_Real QUAD(cutaj);
12954 SCIP_Real QUAD(aj);
12955 SCIP_VAR* var;
12956 int v = indices[i];
12957 int sign;
12958 int type;
12959
12960 assert(0 <= v && v < data->nvars);
12961 assert(data->cutinds[cutindex] == v);
12962 sign = varsign[cutindex];
12963 assert(sign == +1 || sign == -1);
12964 type = boundtype[cutindex];
12965
12966 --cutindex;
12967
12968 var = data->vars[v];
12969 assert(var != NULL);
12971
12972 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
12973
12974 if( enfintegral || implintegral )
12975 {
12976 /* Variable is integral */
12977 SCIP_Real QUAD(downaj);
12978 SCIP_Real QUAD(fj);
12979
12980 /* calculate the coefficient in the retransformed cut */
12981 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
12982 QUAD_SCALE(aj, sign);
12983 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
12984 SCIPquadprecSumQQ(fj, aj, -downaj);
12985 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
12986
12987 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
12988 QUAD_ASSIGN_Q(cutaj, downaj); /* a_j */
12989 else
12990 {
12991 SCIP_Real pj;
12992
12993 SCIPquadprecSumQQ(cutaj, fj, -f0);
12994 SCIPquadprecProdQD(cutaj, cutaj, k);
12995 SCIPquadprecProdQQ(cutaj, cutaj, onedivoneminusf0);
12996 pj = SCIPceil(scip, QUAD_TO_DBL(cutaj));
12997 assert(pj >= 0); /* should be >= 1, but due to rounding bias can be 0 if fj is almost equal to f0 */
12998 assert(pj <= k);
12999 SCIPquadprecDivDD(cutaj, pj, k + 1.0);
13000 SCIPquadprecSumQQ(cutaj, cutaj, downaj);
13001 }
13002
13003 QUAD_SCALE(cutaj, sign);
13004 }
13005 else
13006 {
13007 /* Variable is continuous; must always be positive in strongcg cut. It will be automatically deleted. */
13009 assert(QUAD_TO_DBL(aj) * sign >= 0.0);
13010 QUAD_ASSIGN(cutaj, 0.0);
13011 }
13012
13013 /* remove coefficient from cut if it becomes zero */
13014 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
13015 {
13016 QUAD_ASSIGN(cutaj, 0.0);
13017 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
13018 --data->totalnnz;
13019 --data->secnnz[s];
13020 indices[i] = indices[data->secnnz[s]];
13021 continue;
13022 }
13023
13024 /* store the updated coefficient */
13025 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
13026
13027 /* undo bound transformations. */
13028 if( type < 0 )
13029 {
13030 /* standard bound */
13031 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
13032 if( sign == +1 )
13033 {
13034 /* lower bound was used */
13035 if( type == -1 )
13036 {
13039 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13040 }
13041 else
13042 {
13045 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13046 }
13047 }
13048 else
13049 {
13050 /* upper bound was used */
13051 if( type == -1 )
13052 {
13055 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13056 }
13057 else
13058 {
13061 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13062 }
13063 }
13064 }
13065 else
13066 {
13067 /* variable bound */
13068 SCIP_VAR** vbz;
13069 SCIP_Real* vbb;
13070 SCIP_Real* vbd;
13071 SCIP_Real QUAD(zcoef);
13072 int vbidx;
13073 int zidx;
13074
13075 /* variable bound */
13076 vbidx = type;
13077
13078 /* change mirrhs and cutaj of integer variable z_j of variable bound */
13079 if( sign == +1 )
13080 {
13081 /* variable lower bound was used */
13082 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
13083 vbz = SCIPvarGetVlbVars(var);
13084 vbb = SCIPvarGetVlbCoefs(var);
13086 }
13087 else
13088 {
13089 /* variable upper bound was used */
13090 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
13091 vbz = SCIPvarGetVubVars(var);
13092 vbb = SCIPvarGetVubCoefs(var);
13094 }
13095 assert(SCIPvarIsActive(vbz[vbidx]));
13096 zidx = SCIPvarGetProbindex(vbz[vbidx]);
13097 assert(varSection(data, zidx) > s);
13098
13099 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
13100 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13101
13102 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
13103 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
13104
13105 /* update sparsity pattern */
13106 if( QUAD_HI(zcoef) == 0.0 )
13107 {
13108 int zsection = varSection(data, zidx);
13109 data->secindices[zsection][data->secnnz[zsection]] = zidx;
13110 ++data->secnnz[zsection];
13111 ++data->totalnnz;
13112 }
13113
13114 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
13115 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
13116 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
13117 assert(QUAD_HI(zcoef) != 0.0);
13118 }
13119 }
13120 }
13121
13122 /* Finally, store the relevant data in cutinds which is the array used by the other functions */
13123 data->ncutinds = 0;
13124 for( s = 0; s < NSECTIONS; ++s )
13125 {
13126 int* indices = data->secindices[s];
13127 int nnz = data->secnnz[s];
13128 for( i = 0; i < nnz; ++i )
13129 {
13130 data->cutinds[data->ncutinds] = indices[i];
13131 ++data->ncutinds;
13132 }
13133 }
13134
13135 return SCIP_OKAY;
13136}
13137
13138/** substitute aggregated slack variables:
13139 *
13140 * The coefficient of the slack variable \f$s_r\f$ is equal to the row's weight times the slack's sign, because the slack
13141 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r] \f$.
13142 *
13143 * Depending on the slack's type (integral or continuous), its coefficient in the cut calculates as follows:
13144 * \f[
13145 * \begin{array}{rll}
13146 * integers: & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & if \qquad f_r \leq f_0 \\
13147 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + p_r/(k + 1), & if \qquad f_r > f_0 \\
13148 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & if \qquad a^\prime_r \geq 0 \\
13149 * & \mbox{no strong CG cut found}, & if \qquad a^\prime_r < 0
13150 * \end{array}
13151 * \f]
13152 *
13153 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
13154 */
13155static
13157 SCIP* scip, /**< SCIP datastructure */
13158 SCIP_Real* weights, /**< row weights in row summation */
13159 int* slacksign, /**< stores the sign of the row's slack variable in summation */
13160 int* rowinds, /**< sparsity pattern of used rows */
13161 int nrowinds, /**< number of used rows */
13162 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
13163 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
13164 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
13165 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
13166 int* nnz, /**< number of non-zeros in cut */
13167 QUAD(SCIP_Real f0), /**< fractional value of rhs */
13168 SCIP_Real k /**< factor to strengthen strongcg cut */
13169 )
13170{ /*lint --e{715}*/
13171 SCIP_ROW** rows;
13172 SCIP_Real QUAD(onedivoneminusf0);
13173 int i;
13174
13175 assert(scip != NULL);
13176 assert(weights != NULL);
13177 assert(slacksign != NULL);
13178 assert(rowinds != NULL);
13179 assert(SCIPisPositive(scip, scale));
13180 assert(cutcoefs != NULL);
13181 assert(QUAD_HI(cutrhs) != NULL);
13182 assert(cutinds != NULL);
13183 assert(nnz != NULL);
13184 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
13185
13186 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
13187 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
13188
13189 rows = SCIPgetLPRows(scip);
13190 for( i = 0; i < nrowinds; i++ )
13191 {
13192 SCIP_ROW* row;
13193 SCIP_Real QUAD(ar);
13194 SCIP_Real QUAD(downar);
13195 SCIP_Real QUAD(cutar);
13196 SCIP_Real QUAD(fr);
13197 SCIP_Real mul;
13198 int r;
13199
13200 r = rowinds[i];
13201 assert(0 <= r && r < SCIPgetNLPRows(scip));
13202 assert(slacksign[i] == -1 || slacksign[i] == +1);
13203 assert(!SCIPisZero(scip, weights[i]));
13204
13205 row = rows[r];
13206 assert(row != NULL);
13207 assert(row->len == 0 || row->cols != NULL);
13208 assert(row->len == 0 || row->cols_index != NULL);
13209 assert(row->len == 0 || row->vals != NULL);
13210
13211 /* get the slack's coefficient a'_r in the aggregated row */
13212 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
13213
13214 /* calculate slack variable's coefficient a_r in the cut */
13215 if( row->integral )
13216 {
13217 /* slack variable is always integral */
13218 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
13219 SCIPquadprecSumQQ(fr, ar, -downar);
13220 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
13221
13222 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
13223 QUAD_ASSIGN_Q(cutar, downar); /* a_r */
13224 else
13225 {
13226 SCIP_Real pr;
13227
13228 SCIPquadprecSumQQ(cutar, fr, -f0);
13229 SCIPquadprecProdQD(cutar, cutar, k);
13230 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
13231 pr = SCIPceil(scip, QUAD_TO_DBL(cutar));
13232 assert(pr >= 0); /* should be >= 1, but due to rounding bias can be 0 if fr is almost equal to f0 */
13233 assert(pr <= k);
13234 SCIPquadprecDivDD(cutar, pr, k + 1.0);
13235 SCIPquadprecSumQQ(cutar, cutar, downar);
13236 }
13237 }
13238 else
13239 {
13240 /* slack variable is continuous: */
13241 assert(QUAD_TO_DBL(ar) >= 0.0);
13242 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
13243 }
13244
13245 /* if the coefficient was reduced to zero, ignore the slack variable */
13246 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
13247 continue;
13248
13249 /* depending on the slack's sign, we have
13250 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
13251 * substitute a_r * s_r by adding a_r times the slack's definition to the cut.
13252 */
13253 mul = -slacksign[i] * QUAD_TO_DBL(cutar);
13254
13255 /* add the slack's definition multiplied with a_j to the cut */
13256 SCIP_CALL( varVecAddScaledRowCoefsQuad(cutinds, cutcoefs, nnz, row, mul) );
13257
13258 /* move slack's constant to the right hand side */
13259 if( slacksign[i] == +1 )
13260 {
13261 SCIP_Real rhs;
13262
13263 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a_r * (rhs - c) to the right hand side */
13264 assert(!SCIPisInfinity(scip, row->rhs));
13265 rhs = row->rhs - row->constant;
13266 if( row->integral )
13267 {
13268 /* the right hand side was implicitly rounded down in row aggregation */
13269 rhs = SCIPfloor(scip, rhs);
13270 }
13271
13272 SCIPquadprecProdQD(cutar, cutar, rhs);
13273 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -cutar);
13274 }
13275 else
13276 {
13277 SCIP_Real lhs;
13278
13279 /* a*x + c - s == lhs => s == a*x + c - lhs: move a_r * (c - lhs) to the right hand side */
13280 assert(!SCIPisInfinity(scip, -row->lhs));
13281 lhs = row->lhs - row->constant;
13282 if( row->integral )
13283 {
13284 /* the left hand side was implicitly rounded up in row aggregation */
13285 lhs = SCIPceil(scip, lhs);
13286 }
13287
13288 SCIPquadprecProdQD(cutar, cutar, lhs);
13289 SCIPquadprecSumQQ(*cutrhs, *cutrhs, cutar);
13290 }
13291 }
13292
13293 /* relax rhs to zero, if it's very close to 0 */
13294 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
13295 QUAD_ASSIGN(*cutrhs, 0.0);
13296
13297 return SCIP_OKAY;
13298}
13299
13300
13301/** calculates a strong CG cut out of the weighted sum of LP rows given by an aggregation row; the
13302 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
13303 * participate in a strongcg cut
13304 *
13305 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
13306 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
13307 *
13308 * @pre This method can be called if @p scip is in one of the following stages:
13309 * - \ref SCIP_STAGE_SOLVING
13310 *
13311 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
13312 */
13314 SCIP* scip, /**< SCIP data structure */
13315 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
13316 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
13317 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
13318 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
13319 * type substitution is allowed. The indices are: 0: continuous,
13320 * 1: continuous implint., 2: integer implint, 3: binary implint,
13321 * 4: integer, 5: binary */
13322 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
13323 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce strong CG cut for */
13324 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce strong CG cut for */
13325 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
13326 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute a strong CG cut for */
13327 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
13328 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
13329 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
13330 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
13331 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
13332 int* cutrank, /**< pointer to return rank of generated cut */
13333 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
13334 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
13335 )
13336{
13337 int i;
13338 int nvars;
13339 int* varsign;
13340 int* boundtype;
13341 SCIP_Real QUAD(downrhs);
13342 SCIP_Real QUAD(f0);
13343 SCIP_Real QUAD(tmp);
13344 SCIP_Real large;
13345 SCIP_Real k;
13346 SCIP_Bool freevariable;
13347 SCIP_Bool localbdsused;
13348 MIR_DATA* data;
13349
13350 assert(scip != NULL);
13351 assert(aggrrow != NULL);
13352 assert(SCIPisPositive(scip, scale));
13353 assert(cutcoefs != NULL);
13354 assert(cutrhs != NULL);
13355 assert(cutinds != NULL);
13356 assert(success != NULL);
13357 assert(cutislocal != NULL);
13358
13359 SCIPdebugMsg(scip, "calculating strong CG cut (scale: %g)\n", scale);
13360
13361 *success = FALSE;
13362
13363 /* determine value from which fractionalities are no longer reliable within tolerance */
13365
13366 /* terminate if an integral slack fractionality is unreliable or a negative continuous slack variable is present */
13367 for( i = 0; i < aggrrow->nrows; ++i )
13368 {
13369 if( ( scip->lp->rows[aggrrow->rowsinds[i]]->integral && ABS(aggrrow->rowweights[i] * scale) > large )
13370 || ( !scip->lp->rows[aggrrow->rowsinds[i]]->integral && aggrrow->rowweights[i] * aggrrow->slacksign[i] < 0.0 ) )
13371 return SCIP_OKAY;
13372 }
13373
13374 /* allocate temporary memory */
13377 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
13378
13379 /* Initialize cut data */
13380 int l;
13381 int nnz;
13382
13383 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
13384
13385 SCIP_CALL( SCIPallocBuffer(scip, &data) );
13386
13387 nnz = aggrrow->nnz;
13388 data->totalnnz = nnz;
13389
13390 /* initialize sections */
13391 for( l = 0; l < NSECTIONS; ++l )
13392 {
13393 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
13394 data->secnnz[l] = 0;
13395 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
13396 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
13397 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
13398 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
13399 /* Use variable bounds for the sections specified by the user */
13400 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
13401 }
13402
13403 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
13404 data->vars = SCIPgetVars(scip);
13405 data->nvars = SCIPgetNVars(scip);
13406 data->nbinvars = SCIPgetNBinVars(scip);
13407 data->nintvars = SCIPgetNIntVars(scip);
13412
13414 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
13415
13416 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, scale);
13417
13418 if( nnz > 0 )
13419 {
13420 /* Initalize cut with the aggregation */
13421 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
13422
13423 for( l = 0; l < nnz; ++l )
13424 {
13425 SCIP_Real QUAD(coef);
13426 int m = aggrrow->inds[l];
13427
13428 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
13429
13430 SCIPquadprecProdQD(coef, coef, scale);
13431
13432 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
13433
13434 assert(QUAD_HI(coef) != 0.0);
13435 }
13436
13437 /* Sort the array by problem index and add the variables to their sections */
13438 SCIPsortDownInt(data->cutinds, nnz);
13439 for( l = 0; l < nnz; ++l )
13440 {
13441 int section = varSection(data, data->cutinds[l]);
13442 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
13443 ++data->secnnz[section];
13444 }
13445 }
13446
13447 data->ncutinds = 0;
13448 *cutislocal = aggrrow->local;
13449
13450 if( data->totalnnz > 0 )
13451 {
13452 int firstcontvar;
13453
13454 /* Transform equation a*x == b, lb <= x <= ub into standard form
13455 * a'*x' == b, 0 <= x' <= ub'.
13456 *
13457 * Transform variables (lb or ub):
13458 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
13459 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
13460 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
13461 *
13462 * Transform variables (vlb or vub):
13463 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
13464 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
13465 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
13466 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
13467 * a_{zu_j} := a_{zu_j} + a_j * bu_j
13468 */
13469 SCIP_CALL( cutsTransformStrongCG(scip, data, sol, boundswitch, allowlocal, varsign, boundtype, &freevariable, &localbdsused) );
13470
13471 if( freevariable )
13472 goto TERMINATE;
13473
13474 assert(allowlocal || !localbdsused);
13475 *cutislocal = *cutislocal || localbdsused;
13476
13477 firstcontvar = nvars - SCIPgetNContVars(scip);
13478
13479 /* terminate if an integral coefficient fractionality is unreliable */
13480 for( i = data->ncutinds - 1; i >= 0 && data->cutinds[i] < firstcontvar; --i )
13481 {
13482 SCIP_Real QUAD(coef);
13483
13484 QUAD_ARRAY_LOAD(coef, data->cutcoefs, data->cutinds[i]);
13485
13486 if( ABS(QUAD_TO_DBL(coef)) > large )
13487 goto TERMINATE;
13488 }
13489
13490 SCIPdebug(printCutQuad(scip, NULL, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
13491 }
13492
13493 /* terminate if the side fractionality is unreliable */
13494 if( ABS(QUAD_TO_DBL(data->cutrhs)) > large )
13495 goto TERMINATE;
13496
13497 /* Calculate
13498 * - fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j)
13499 * - integer k >= 1 with 1/(k + 1) <= f_0 < 1/k
13500 * (=> k = up(1/f_0) - 1)
13501 * - integer 1 <= p_j <= k with f_0 + ((p_j - 1) * (1 - f_0)/k) < f_j <= f_0 + (p_j * (1 - f_0)/k)
13502 * (=> p_j = up( (f_j - f_0)/((1 - f_0)/k) ))
13503 * and derive strong CG cut
13504 * a~*x' <= (k+1) * down(b)
13505 * integers : a~_j = down(a'_j) , if f_j <= f_0
13506 * a~_j = down(a'_j) + p_j/(k + 1) , if f_j > f_0
13507 * continuous: a~_j = 0 , if a'_j >= 0
13508 * no strong CG cut found , if a'_j < 0
13509 *
13510 * Transform inequality back to a^*x <= rhs:
13511 *
13512 * (lb or ub):
13513 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
13514 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
13515 * and move the constant terms
13516 * -a~_j * lb_j == -a^_j * lb_j, or
13517 * a~_j * ub_j == -a^_j * ub_j
13518 * to the rhs.
13519 *
13520 * (vlb or vub):
13521 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
13522 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
13523 * move the constant terms
13524 * -a~_j * dl_j == -a^_j * dl_j, or
13525 * a~_j * du_j == -a^_j * du_j
13526 * to the rhs, and update the VB variable coefficients:
13527 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
13528 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
13529 */
13530 SCIPquadprecEpsFloorQ(downrhs, data->cutrhs, SCIPepsilon(scip)); /*lint !e666*/
13531 SCIPquadprecSumQQ(f0, data->cutrhs, -downrhs);
13532 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
13533
13534 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
13535 goto TERMINATE;
13536
13537 /* renormalize the f0 value */
13538 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
13539
13540 SCIPquadprecDivDQ(tmp, 1.0, f0);
13541 SCIPquadprecSumQD(tmp, tmp, -1.0);
13542 k = SCIPceil(scip, QUAD_TO_DBL(tmp));
13543 QUAD_ASSIGN_Q(data->cutrhs, downrhs);
13544
13545 if( data->totalnnz > 0 )
13546 {
13547 SCIP_CALL( cutsRoundStrongCG(scip, data, varsign, boundtype, QUAD(f0), k) );
13548 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
13549 }
13550
13551 /* substitute aggregated slack variables:
13552 *
13553 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
13554 * variable only appears in its own row:
13555 * a'_r = scale * weight[r] * slacksign[r].
13556 *
13557 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
13558 * integers : a_r = a~_r = (k + 1) * down(a'_r) , if f_r <= f0
13559 * a_r = a~_r = (k + 1) * down(a'_r) + p_r , if f_r > f0
13560 * continuous: a_r = a~_r = 0 , if a'_r >= 0
13561 * a_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
13562 *
13563 * Substitute a_r * s_r by adding a_r times the slack's definition to the cut.
13564 */
13565 SCIP_CALL( cutsSubstituteStrongCG(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
13566 aggrrow->nrows, scale, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds, QUAD(f0), k) );
13567 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
13568
13569 /* remove all nearly-zero coefficients from strong CG row and relax the right hand side correspondingly in order to
13570 * prevent numerical rounding errors
13571 */
13572 if( postprocess )
13573 {
13574 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, data->cutinds, data->cutcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
13575 }
13576 else
13577 {
13578 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds);
13579 }
13580 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
13581
13582 if( *success )
13583 {
13584 *cutrhs = QUAD_TO_DBL(data->cutrhs);
13585 *cutnnz = data->ncutinds;
13586
13587 /* store cut in given array in sparse representation and clean buffer array */
13588 for( i = 0; i < *cutnnz; ++i )
13589 {
13590 SCIP_Real QUAD(coef);
13591 int j = data->cutinds[i];
13592
13593 QUAD_ARRAY_LOAD(coef, data->cutcoefs, j);
13594 assert(QUAD_HI(coef) != 0.0);
13595
13596 cutcoefs[i] = QUAD_TO_DBL(coef);
13597 cutinds[i] = j;
13598 QUAD_ASSIGN(coef, 0.0);
13599 QUAD_ARRAY_STORE(data->cutcoefs, j, coef);
13600 }
13601
13602 if( cutefficacy != NULL )
13603 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
13604
13605 if( cutrank != NULL )
13606 *cutrank = aggrrow->rank + 1;
13607 }
13608
13609 TERMINATE:
13610
13611 /* if we aborted early the temporary coefficients need to be cleaned */
13612 if( !(*success) )
13613 {
13614 QUAD_ASSIGN(tmp, 0.0);
13615
13616 for( i = 0; i < data->ncutinds; ++i )
13617 {
13618 QUAD_ARRAY_STORE(data->cutcoefs, data->cutinds[i], tmp);
13619 }
13620 }
13621
13622 if( data->cutinds != NULL )
13624
13625 if( data->cutcoefs != NULL )
13627
13628 for( int s = NSECTIONS - 1; s >= 0; --s )
13629 {
13631 }
13632
13633 SCIPfreeBuffer(scip, &data);
13634
13635 /* free temporary memory */
13636 SCIPfreeBufferArray(scip, &boundtype);
13637 SCIPfreeBufferArray(scip, &varsign);
13638
13639 return SCIP_OKAY;
13640}
13641
13642/** initializes cut generation parameters with default values */
13644 SCIP_CUTGENPARAMS* params /**< pointer to parameters to initialize */
13645 )
13646{
13647 assert(params != NULL);
13648
13654 params->boundsfortrans = NULL;
13655 params->boundtypesfortrans = NULL;
13658}
13659
13660/** creates a cut generation result structure and allocates arrays for cut coefficients and indices
13661 *
13662 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
13663 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
13664 */
13666 SCIP* scip, /**< SCIP data structure */
13667 SCIP_CUTGENRESULT** result /**< pointer to store the created result structure */
13668 )
13669{
13670 int nvars;
13671
13672 assert(scip != NULL);
13673 assert(result != NULL);
13674
13676
13678 SCIP_CALL( SCIPallocBufferArray(scip, &(*result)->cutcoefs, nvars) );
13679 SCIP_CALL( SCIPallocBufferArray(scip, &(*result)->cutinds, nvars) );
13680
13681 return SCIP_OKAY;
13682}
13683
13684/** frees a cut generation result structure created by SCIPcreateCutGenResult() */
13686 SCIP* scip, /**< SCIP data structure */
13687 SCIP_CUTGENRESULT** result /**< pointer to the result structure to free */
13688 )
13689{
13690 assert(scip != NULL);
13691 assert(result != NULL);
13692 assert(*result != NULL);
13693
13694 SCIPfreeBufferArray(scip, &(*result)->cutinds);
13695 SCIPfreeBufferArray(scip, &(*result)->cutcoefs);
13697}
13698
13699/** tries multiple cut generation methods on an aggregation row and returns the best cut by efficacy
13700 *
13701 * This function attempts to generate cuts using the specified methods.
13702 * Each method only returns a cut if it improves upon the previous best efficacy.
13703 * See type_cuts.h for available SCIP_CUTGENMETHOD_* flags.
13704 *
13705 * Use SCIPinitCutGenParams() to initialize parameters with default values.
13706 * Use SCIPcreateCutGenResult() to create the result structure, or manually set result->cutcoefs and result->cutinds
13707 * to point to arrays of size at least SCIPgetNVars(scip).
13708 * Use SCIPfreeCutGenResult() to free the result structure when done.
13709 *
13710 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
13711 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
13712 *
13713 * @pre This method can be called if @p scip is in one of the following stages:
13714 * - \ref SCIP_STAGE_SOLVING
13715 */
13717 SCIP* scip, /**< SCIP data structure */
13718 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
13719 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute cuts for */
13720 SCIP_CUTGENMETHOD methods, /**< bit field indicating which methods to try (SCIP_CUTGENMETHOD_*) */
13721 SCIP_CUTGENPARAMS* params, /**< cut generation parameters */
13722 SCIP_CUTGENRESULT* result /**< pointer to result structure (cutcoefs and cutinds pre-allocated) */
13723 )
13724{
13725 SCIP_Real cutrhs;
13726 SCIP_Real efficacy;
13727 SCIP_Bool cutislocal;
13728 SCIP_Bool success;
13729 int cutnnz;
13730 int cutrank;
13731
13732 assert(scip != NULL);
13733 assert(aggrrow != NULL);
13734 assert(aggrrow->nnz >= 0);
13735 assert(methods != SCIP_CUTGENMETHOD_NONE);
13736 assert(params != NULL);
13737 assert(result != NULL);
13738 assert(result->cutcoefs != NULL);
13739 assert(result->cutinds != NULL);
13740
13741 /* initialize result */
13742 result->winningmethod = SCIP_CUTGENMETHOD_NONE;
13743 result->cutefficacy = -SCIPinfinity(scip);
13744 result->cutrhs = 0.0;
13745 result->cutnnz = 0;
13746 result->cutrank = 0;
13747 result->cutislocal = FALSE;
13748 result->success = FALSE;
13749
13750 /* bail out early if the aggregation row is empty */
13751 if( aggrrow->nnz == 0 )
13752 return SCIP_OKAY;
13753
13754 /* Each cut generation method writes to local variables and only succeeds if the generated cut has efficacy strictly
13755 * better than the input efficacy. We copy results only on success.
13756 */
13757
13758 /* try FlowCover */
13759 if( methods & SCIP_CUTGENMETHOD_FLOWCOVER )
13760 {
13761 efficacy = result->cutefficacy;
13762 SCIP_CALL( SCIPcalcFlowCover(scip, sol, params->postprocess, params->boundswitch, params->allowlocal, aggrrow,
13763 result->cutcoefs, &cutrhs, result->cutinds, &cutnnz, &efficacy, &cutrank, &cutislocal, &success) );
13764
13765 if( success )
13766 {
13767 result->winningmethod = SCIP_CUTGENMETHOD_FLOWCOVER;
13768 result->cutefficacy = efficacy;
13769 result->cutrhs = cutrhs;
13770 result->cutnnz = cutnnz;
13771 result->cutrank = cutrank;
13772 result->cutislocal = cutislocal;
13773 result->success = TRUE;
13774 }
13775 }
13776
13777 /* try KnapsackCover */
13778 if( methods & SCIP_CUTGENMETHOD_KNAPSACKCOVER )
13779 {
13780 efficacy = result->cutefficacy;
13782 result->cutcoefs, &cutrhs, result->cutinds, &cutnnz, &efficacy, &cutrank, &cutislocal, &success) );
13783
13784 if( success )
13785 {
13786 result->winningmethod = SCIP_CUTGENMETHOD_KNAPSACKCOVER;
13787 result->cutefficacy = efficacy;
13788 result->cutrhs = cutrhs;
13789 result->cutnnz = cutnnz;
13790 result->cutrank = cutrank;
13791 result->cutislocal = cutislocal;
13792 result->success = TRUE;
13793 }
13794 }
13795
13796 /* try CMIR */
13797 if( methods & SCIP_CUTGENMETHOD_CMIR )
13798 {
13799 efficacy = result->cutefficacy;
13801 params->vartypeusevbds, params->allowlocal, params->maxtestdelta, params->boundsfortrans,
13802 params->boundtypesfortrans, params->minfrac, params->maxfrac, aggrrow,
13803 result->cutcoefs, &cutrhs, result->cutinds, &cutnnz, &efficacy, &cutrank, &cutislocal, &success) );
13804
13805 if( success )
13806 {
13807 result->winningmethod = SCIP_CUTGENMETHOD_CMIR;
13808 result->cutefficacy = efficacy;
13809 result->cutrhs = cutrhs;
13810 result->cutnnz = cutnnz;
13811 result->cutrank = cutrank;
13812 result->cutislocal = cutislocal;
13813 result->success = TRUE;
13814 }
13815 }
13816
13817 return SCIP_OKAY;
13818}
SCIP_CERTIFICATE * SCIPgetCertificate(SCIP *scip)
methods for certificate output
SCIP_VAR * h
SCIP_VAR ** x
#define MAXABSVBCOEF
#define MAXDNOM
static SCIP_Real computeMIREfficacy(SCIP *scip, SCIP_Real *RESTRICT coefs, SCIP_Real *RESTRICT solvals, SCIP_Real rhs, SCIP_Real contactivity, SCIP_Real contsqrnorm, SCIP_Real delta, int nvars, SCIP_Real minfrac, SCIP_Real maxfrac)
Definition cuts.c:8268
static SCIP_RETCODE cutsRoundMIRSafely(SCIP *scip, SCIP_Real *RESTRICT cutcoefs, SCIP_Real *RESTRICT cutrhs, int *RESTRICT cutinds, int *RESTRICT nnz, int *RESTRICT varsign, int *RESTRICT boundtype, SCIP_INTERVAL f0)
Definition cuts.c:5883
struct MIR_Data MIR_DATA
static SCIP_RETCODE cutsSubstituteMIR(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz,)
Definition cuts.c:7488
static SCIP_RETCODE findBestUb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, int *bestubtype)
Definition cuts.c:4572
static SCIP_Bool chgQuadCoeffWithBound(SCIP *scip, SCIP_VAR *var, QUAD(SCIP_Real oldcoeff), SCIP_Real newcoeff, SCIP_Bool cutislocal,)
Definition cuts.c:1108
static SCIP_RETCODE findBestLbSafely(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, SCIP_Real *simplebound, int *bestlbtype)
Definition cuts.c:4175
static SCIP_RETCODE varVecAddScaledRowCoefsSafely(SCIP *scip, int *inds, SCIP_Real *vals, int *nnz, SCIP_ROW *row, SCIP_Real scale, SCIP_Real *rhschange, SCIP_Bool *success)
Definition cuts.c:363
static void performBoundSubstitutionSimple(SCIP *scip, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition cuts.c:5272
static void prepareLiftingData(SCIP *scip, SCIP_Real *cutcoefs, int *cutinds, QUAD(SCIP_Real cutrhs), int *coverpos, int coversize, QUAD(SCIP_Real coverweight), SCIP_Real *covervals, int *coverstatus, QUAD(SCIP_Real *abar), int *cplussize)
Definition cuts.c:12086
static SCIP_RETCODE postprocessCutSafely(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, SCIP_Real *cutrhs, SCIP_Bool *success)
Definition cuts.c:3899
static SCIP_RETCODE cutsTransformKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *localbdsused, SCIP_Bool *success)
Definition cuts.c:11801
static SCIP_Bool removeZerosSafely(SCIP *scip, SCIP_Real minval, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz)
Definition cuts.c:738
static SCIP_Real calcEfficacyDenseStorageQuad(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition cuts.c:661
#define DEFAULT_CUTGEN_VARTYPEUSEVBDS
Definition cuts.c:73
static SCIP_Bool removeZerosQuad(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
Definition cuts.c:833
static SCIP_RETCODE cutsRoundStrongCG(SCIP *scip, MIR_DATA *data, int *varsign, int *boundtype, QUAD(SCIP_Real f0), SCIP_Real k)
Definition cuts.c:12916
static SCIP_RETCODE findBestUbSafely(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, SCIP_Real *simplebound, int *bestubtype)
Definition cuts.c:4244
static SCIP_RETCODE cutsSubstituteStrongCG(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, QUAD(SCIP_Real f0), SCIP_Real k)
Definition cuts.c:13156
static SCIP_RETCODE computeLiftingData(SCIP *scip, SNF_RELAXATION *snf, int *transvarflowcoverstatus, SCIP_Real lambda, LIFTINGDATA *liftingdata, SCIP_Bool *valid)
Definition cuts.c:11232
static void doMIRBoundSubstitution(SCIP *scip, MIR_DATA *data, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition cuts.c:5020
static SCIP_RETCODE getClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestsub, SCIP_Real rowcoef, SCIP_Real *closestvlb, int *closestvlbidx)
Definition cuts.c:9201
static SCIP_RETCODE getFlowCover(SCIP *scip, SNF_RELAXATION *snf, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, SCIP_Real *lambda, SCIP_Bool *found)
Definition cuts.c:10844
static SCIP_RETCODE getClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestslb, SCIP_Real rowcoef, SCIP_Real *closestvub, int *closestvubidx)
Definition cuts.c:9330
static SCIP_RETCODE varVecAddScaledRowCoefsQuadScale(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row,)
Definition cuts.c:298
static SCIP_RETCODE cutsRoundMIR(SCIP *scip, MIR_DATA *data, int *RESTRICT varsign, int *RESTRICT boundtype,)
Definition cuts.c:6721
static SCIP_Real evaluateLiftingFunctionKnapsack(SCIP *scip, QUAD(SCIP_Real x), QUAD(SCIP_Real abar), SCIP_Real *covervals, int coversize, int cplussize, SCIP_Real *scale)
Definition cuts.c:12202
#define MAXBOUND
Definition cuts.c:9153
static SCIP_Real scaleValSafely(SCIP *scip, SCIP_Real val, SCIP_Real scale, SCIP_Bool cutislocal, SCIP_VAR *var, SCIP_Real *rhschange, SCIP_Bool *success)
Definition cuts.c:1596
static SCIP_RETCODE findBestLb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, int *bestlbtype)
Definition cuts.c:4509
static SCIP_RETCODE cutsTransformMIR(SCIP *scip, MIR_DATA *data, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition cuts.c:5554
static SCIP_RETCODE constructSNFRelaxation(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_Real *rowcoefs, QUAD(SCIP_Real rowrhs), int *rowinds, int nnz, SNF_RELAXATION *snf, SCIP_Bool *success, SCIP_Bool *localbdsused)
Definition cuts.c:9638
static SCIP_RETCODE postprocessCutQuad(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, QUAD(SCIP_Real *cutrhs), SCIP_Bool *success)
Definition cuts.c:3833
#define DEFAULT_CUTGEN_MAXFRAC
Definition cuts.c:75
static SCIP_Bool chgCoeffWithBound(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal,)
Definition cuts.c:1063
static SCIP_RETCODE calcMIRSafely(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, 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:7648
static int varSection(MIR_DATA *data, int probindex)
Definition cuts.c:4135
static void performBoundSubstitution(SCIP *scip, int *cutinds, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *nnz, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition cuts.c:5191
static void destroyLiftingData(SCIP *scip, LIFTINGDATA *liftingdata)
Definition cuts.c:11362
static void performBoundSubstitutionSimpleSafely(SCIP *scip, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition cuts.c:5157
static SCIP_RETCODE findMIRBestLb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, MIR_DATA *data, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, SCIP_Real *simplebound, int *bestlbtype)
Definition cuts.c:4637
static SCIP_RETCODE varVecAddScaledRowCoefsQuad(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition cuts.c:251
static SCIP_Real calcEfficacyNormQuad(SCIP *scip, SCIP_Real *vals, int *inds, int nnz)
Definition cuts.c:528
#define NSECTIONS
Definition cuts.c:4099
static SCIP_RETCODE cutTightenCoefs(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
Definition cuts.c:2114
static SCIP_RETCODE determineBestBounds(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, MIR_DATA *data, SCIP_Real boundswitch, int usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real *bestlb, SCIP_Real *bestub, int *bestlbtype, int *bestubtype, SCIP_BOUNDTYPE *selectedbound, SCIP_Bool *freevariable)
Definition cuts.c:4814
#define DEFAULT_CUTGEN_BOUNDSWITCH
Definition cuts.c:71
#define NONZERO(x)
Definition cuts.c:200
static SCIP_Bool removeZeros(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
Definition cuts.c:926
#define DEFAULT_CUTGEN_MAXTESTDELTA
Definition cuts.c:76
struct LiftingData LIFTINGDATA
static SCIP_RETCODE SCIPsolveKnapsackApproximatelyLT(SCIP *scip, int nitems, SCIP_Real *weights, SCIP_Real *profits, SCIP_Real capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
Definition cuts.c:10233
static SCIP_Real calcEfficacyDenseStorage(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition cuts.c:590
static SCIP_RETCODE determineBoundForSNF(SCIP *scip, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *rowcoefs, int *rowinds, int varposinrow, int8_t *binvarused, SCIP_Bool allowlocal, SCIP_Real boundswitch, SCIP_Real *bestlb, SCIP_Real *bestub, SCIP_Real *bestslb, SCIP_Real *bestsub, int *bestlbtype, int *bestubtype, int *bestslbtype, int *bestsubtype, SCIP_BOUNDTYPE *selectedbounds, SCIP_Bool *freevariable)
Definition cuts.c:9458
static SCIP_RETCODE postprocessCut(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, SCIP_Real *cutrhs, SCIP_Bool *success)
Definition cuts.c:3764
static void destroySNFRelaxation(SCIP *scip, SNF_RELAXATION *snf)
Definition cuts.c:10213
static SCIP_RETCODE allocSNFRelaxation(SCIP *scip, SNF_RELAXATION *snf, int nvars)
Definition cuts.c:10192
static SCIP_RETCODE addOneRowSafely(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *rowtoolong, SCIP_Bool *rowused, SCIP_Bool *success, SCIP_Bool *lhsused)
Definition cuts.c:3382
#define DEFAULT_CUTGEN_MINFRAC
Definition cuts.c:74
static SCIP_Bool chgCoeffWithBoundSafely(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal, SCIP_Real *cutrhs)
Definition cuts.c:1153
static SCIP_RETCODE cutsSubstituteMIRSafely(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *nnz, SCIP_INTERVAL f0)
Definition cuts.c:6964
static SCIP_Real calcEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition cuts.c:463
static void buildFlowCover(SCIP *scip, int *coefs, SCIP_Real *vubcoefs, SCIP_Real rhs, int *solitems, int *nonsolitems, int nsolitems, int nnonsolitems, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, QUAD(SCIP_Real *flowcoverweight), SCIP_Real *lambda)
Definition cuts.c:10328
#define DEFAULT_CUTGEN_ALLOWLOCAL
Definition cuts.c:72
#define MAXCMIRSCALE
Definition cuts.c:4090
static SCIP_RETCODE generateLiftedFlowCoverCut(SCIP *scip, SNF_RELAXATION *snf, SCIP_AGGRROW *aggrrow, int *flowcoverstatus, SCIP_Real lambda, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *nnz, SCIP_Bool *success)
Definition cuts.c:11375
static SCIP_RETCODE cutsTransformStrongCG(SCIP *scip, MIR_DATA *data, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool allowlocal, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition cuts.c:12629
static SCIP_RETCODE cutTightenCoefsSafely(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Bool *redundant)
Definition cuts.c:1669
static void getAlphaAndBeta(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real vubcoef, int *alpha, SCIP_Real *beta)
Definition cuts.c:11195
static SCIP_Bool computeInitialKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, int *cutinds, SCIP_Real cutrhs, int cutnnz, int *varsign, int *coverstatus, int *coverpos, SCIP_Real *covervals, int *coversize,)
Definition cuts.c:11995
static SCIP_RETCODE addOneRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *rowtoolong)
Definition cuts.c:3268
static SCIP_RETCODE determineBestBoundsSafely(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real boundswitch, int usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real *bestlb, SCIP_Real *bestub, int *bestlbtype, int *bestubtype, SCIP_BOUNDTYPE *selectedbound, SCIP_Bool *freevariable)
Definition cuts.c:4310
static void performBoundSubstitutionSafely(SCIP *scip, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition cuts.c:5110
static SCIP_RETCODE cutsTransformMIRSafely(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition cuts.c:5331
struct SNF_Relaxation SNF_RELAXATION
static SCIP_RETCODE cutTightenCoefsQuad(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
Definition cuts.c:1218
static SCIP_Real evaluateLiftingFunction(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real x)
Definition cuts.c:11111
static SCIP_RETCODE varVecAddScaledRowCoefs(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition cuts.c:206
#define DEFAULT_CUTGEN_POSTPROCESS
Definition cuts.c:70
static SCIP_RETCODE findMIRBestUb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, MIR_DATA *data, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, SCIP_Real *simplebound, int *bestubtype)
Definition cuts.c:4726
methods for the aggregation rows
defines macros for basic operations in double-double arithmetic giving roughly twice the precision of...
#define QUAD_LO(x)
Definition dbldblarith.h:46
#define QUAD_EPSILON
Definition dbldblarith.h:42
#define QUAD_ARRAY_STORE(a, idx, x)
Definition dbldblarith.h:55
#define SCIPquadprecProdDD(r, a, b)
Definition dbldblarith.h:58
#define SCIPquadprecProdQD(r, a, b)
Definition dbldblarith.h:63
#define QUAD_SCALE(x, a)
Definition dbldblarith.h:50
#define SCIPquadprecProdQQ(r, a, b)
Definition dbldblarith.h:66
#define SCIPquadprecSumQD(r, a, b)
Definition dbldblarith.h:62
#define QUAD_ARRAY_SIZE(size)
Definition dbldblarith.h:53
#define SCIPquadprecEpsFloorQ(r, a, eps)
Definition dbldblarith.h:75
#define QUAD_ASSIGN(a, constant)
Definition dbldblarith.h:51
#define SCIPquadprecFloorQ(r, a)
Definition dbldblarith.h:73
#define QUAD(x)
Definition dbldblarith.h:47
#define SCIPquadprecEpsCeilQ(r, a, eps)
Definition dbldblarith.h:76
#define SCIPquadprecSumDD(r, a, b)
Definition dbldblarith.h:60
#define SCIPquadprecSumQQ(r, a, b)
Definition dbldblarith.h:67
#define SCIPquadprecDivDQ(r, a, b)
Definition dbldblarith.h:64
#define QUAD_HI(x)
Definition dbldblarith.h:45
#define QUAD_ASSIGN_Q(a, b)
Definition dbldblarith.h:52
#define QUAD_ARRAY_LOAD(r, a, idx)
Definition dbldblarith.h:54
#define SCIPquadprecDivDD(r, a, b)
Definition dbldblarith.h:61
#define QUAD_TO_DBL(x)
Definition dbldblarith.h:49
#define NULL
Definition def.h:257
#define COPYSIGN
Definition def.h:248
#define SCIP_Longint
Definition def.h:150
#define SCIP_UNUSED(x)
Definition def.h:418
#define EPSISINT(x, eps)
Definition def.h:204
#define SCIP_REAL_MAX
Definition def.h:167
#define SCIP_INVALID
Definition def.h:187
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define SCIP_Real
Definition def.h:165
#define ABS(x)
Definition def.h:225
#define EPSFRAC(x, eps)
Definition def.h:203
#define SQR(x)
Definition def.h:208
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIP_CALL_ABORT(x)
Definition def.h:343
#define RESTRICT
Definition def.h:269
#define SCIPABORT()
Definition def.h:336
#define SCIP_REAL_MIN
Definition def.h:168
#define EPSFLOOR(x, eps)
Definition def.h:200
#define REALABS(x)
Definition def.h:191
#define EPSZ(x, eps)
Definition def.h:197
#define SCIP_CALL(x)
Definition def.h:364
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
int SCIPgetNIntVars(SCIP *scip)
Definition scip_prob.c:2340
int SCIPgetNContVars(SCIP *scip)
Definition scip_prob.c:2569
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 SCIPgetNContImplVars(SCIP *scip)
Definition scip_prob.c:2522
int SCIPgetNBinVars(SCIP *scip)
Definition scip_prob.c:2293
#define SCIPdebugMsgPrint
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
#define SCIPdebugMsg
SCIP_Bool SCIPrealIsExactlyIntegral(SCIP_Real val)
Definition misc.c:9604
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition misc.c:9641
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition misc.c:11162
SCIP_RETCODE SCIPaddCertificateMirInfo(SCIP *scip)
SCIP_Bool SCIPisCertified(SCIP *scip)
SCIP_RETCODE SCIPaddCertificateAggrInfo(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW **aggrrows, SCIP_Real *weights, int naggrrows, SCIP_ROW **negslackrows, SCIP_Real *negslackweights, int nnegslackrows)
void SCIPaggrRowCancelVarWithBound(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_VAR *var, int pos, SCIP_Bool *valid)
Definition cuts.c:3019
SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
Definition cuts.c:4016
SCIP_RETCODE SCIPcutGenerationHeuristicCMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, int maxtestdelta, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, 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:8350
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:7934
int SCIPaggrRowGetRank(SCIP_AGGRROW *aggrrow)
Definition cuts.c:4059
SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
Definition cuts.c:2477
void SCIPaggrRowClearSafely(SCIP_AGGRROW *aggrrow)
Definition cuts.c:3207
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition cuts.c:2679
SCIP_RETCODE SCIPaggrRowAddRowSafely(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype, SCIP_Bool *success)
Definition cuts.c:2898
SCIP_RETCODE SCIPcalcKnapsackCover(SCIP *scip, SCIP_SOL *sol, 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:12302
SCIP_RETCODE SCIPcreateCutGenResult(SCIP *scip, SCIP_CUTGENRESULT **result)
Definition cuts.c:13665
void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
Definition cuts.c:3229
SCIP_RETCODE SCIPaggrRowCopy(SCIP *scip, SCIP_AGGRROW **aggrrow, SCIP_AGGRROW *source)
Definition cuts.c:2769
SCIP_Bool SCIPaggrRowIsLocal(SCIP_AGGRROW *aggrrow)
Definition cuts.c:4069
SCIP_Real SCIPaggrRowGetRhs(SCIP_AGGRROW *aggrrow)
Definition cuts.c:4079
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition scip_cut.c:135
int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
Definition cuts.c:3984
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:3154
SCIP_RETCODE SCIPcalcStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, 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:13313
void SCIPfreeCutGenResult(SCIP *scip, SCIP_CUTGENRESULT **result)
Definition cuts.c:13685
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition cuts.c:2711
void SCIPinitCutGenParams(SCIP_CUTGENPARAMS *params)
Definition cuts.c:13643
SCIP_RETCODE SCIPcalcBestCut(SCIP *scip, SCIP_SOL *sol, SCIP_AGGRROW *aggrrow, SCIP_CUTGENMETHOD methods, SCIP_CUTGENPARAMS *params, SCIP_CUTGENRESULT *result)
Definition cuts.c:13716
int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
Definition cuts.c:4039
void SCIPaggrRowPrint(SCIP *scip, SCIP_AGGRROW *aggrrow, FILE *file)
Definition cuts.c:2732
void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool useglbbounds, SCIP_Bool *valid)
Definition cuts.c:3960
SCIP_Real * SCIPaggrRowGetRowWeights(SCIP_AGGRROW *aggrrow)
Definition cuts.c:4005
int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
Definition cuts.c:4049
SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
Definition cuts.c:2815
int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
Definition cuts.c:3994
SCIP_RETCODE SCIPaggrRowSumRows(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real *weights, int *rowinds, int nrowinds, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *valid)
Definition cuts.c:3534
int SCIPgetNCuts(SCIP *scip)
Definition scip_cut.c:762
SCIP_RETCODE SCIPaggrRowAddObjectiveFunction(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real rhs, SCIP_Real scale)
Definition cuts.c:3078
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:11656
SCIP_Real SCIPaggrRowCalcEfficacyNorm(SCIP *scip, SCIP_AGGRROW *aggrrow)
Definition cuts.c:3254
SCIP_Bool SCIPisExact(SCIP *scip)
Definition scip_exact.c:193
void SCIPintervalSetRoundingModeUpwards(void)
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int SCIP_ROUNDMODE
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
struct SCIP_Interval SCIP_INTERVAL
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSetRational(SCIP_INTERVAL *resultant, SCIP_RATIONAL *value)
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition scip_lp.c:576
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition scip_lp.c:611
int SCIPgetNLPRows(SCIP *scip)
Definition scip_lp.c:632
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition scip_mem.h:146
#define SCIPfreeBuffer(scip, ptr)
Definition scip_mem.h:134
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition scip_mem.h:142
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
BMS_BUFMEM * SCIPbuffer(SCIP *scip)
Definition scip_mem.c:72
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition scip_mem.h:122
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition scip_mem.h:111
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
SCIP_Bool SCIPrationalIsLTReal(SCIP_RATIONAL *rat, SCIP_Real real)
void SCIPrationalMult(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
void SCIPrationalInvert(SCIP_RATIONAL *res, SCIP_RATIONAL *op)
SCIP_Real SCIPrationalGetReal(SCIP_RATIONAL *rational)
void SCIPrationalDiv(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
void SCIPrationalSetReal(SCIP_RATIONAL *res, SCIP_Real real)
Definition rational.cpp:604
void SCIPrationalFreeBuffer(BMS_BUFMEM *bufmem, SCIP_RATIONAL **rational)
Definition rational.cpp:474
void SCIPrationalDiff(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
Definition rational.cpp:984
SCIP_Bool SCIPrationalIsPositive(SCIP_RATIONAL *rational)
SCIP_RETCODE SCIPrationalCreateBuffer(BMS_BUFMEM *bufmem, SCIP_RATIONAL **rational)
Definition rational.cpp:124
SCIP_Bool SCIPrationalIsZero(SCIP_RATIONAL *rational)
void SCIPrationalSetRational(SCIP_RATIONAL *res, SCIP_RATIONAL *src)
Definition rational.cpp:570
SCIP_Bool SCIPrationalIsGEReal(SCIP_RATIONAL *rat, SCIP_Real real)
SCIP_Bool SCIPrationalIsNegative(SCIP_RATIONAL *rational)
void SCIPrationalDiffReal(SCIP_RATIONAL *res, SCIP_RATIONAL *rat, SCIP_Real real)
SCIP_Real SCIPrationalRoundReal(SCIP_RATIONAL *rational, SCIP_ROUNDMODE_RAT roundmode)
SCIP_Bool SCIPrationalIsEQReal(SCIP_RATIONAL *rat, SCIP_Real real)
void SCIPrationalMultReal(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_Real op2)
SCIP_Bool SCIPrationalIsLE(SCIP_RATIONAL *rat1, SCIP_RATIONAL *rat2)
void SCIPrationalAddReal(SCIP_RATIONAL *res, SCIP_RATIONAL *rat, SCIP_Real real)
Definition rational.cpp:962
void SCIPrationalAddProdReal(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_Real op2)
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition lp.c:17686
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition lp.c:17805
SCIP_Real SCIPgetRowMinActivity(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1903
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition lp.c:17696
SCIP_Real SCIPgetRowMaxActivity(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1920
int SCIProwGetLPPos(SCIP_ROW *row)
Definition lp.c:17895
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition lp.c:17795
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
SCIP_RETCODE SCIPcaptureRow(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1486
SCIP_ROWEXACT * SCIProwGetRowExact(SCIP_ROW *row)
Definition lp.c:17959
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition lp.c:17734
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition scip_lp.c:2108
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 SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetHugeValue(SCIP *scip)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Real SCIPsumepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisSumLE(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 SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:23674
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_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23932
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23485
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
SCIP_RETCODE SCIPgetVarClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvub, int *closestvubidx)
Definition scip_var.c:8592
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:23694
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition var.c:24546
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition var.c:24556
SCIP_RATIONAL * SCIPvarGetUbLocalExact(SCIP_VAR *var)
Definition var.c:24310
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_RETCODE SCIPgetVarClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvlb, int *closestvlbidx)
Definition scip_var.c:8569
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition var.c:24696
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_RATIONAL * SCIPvarGetLbGlobalExact(SCIP_VAR *var)
Definition var.c:24162
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition var.c:24526
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_RATIONAL * SCIPvarGetLbLocalExact(SCIP_VAR *var)
Definition var.c:24276
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_RATIONAL * SCIPvarGetUbGlobalExact(SCIP_VAR *var)
Definition var.c:24184
void SCIPselectWeightedDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
void SCIPsortDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, int len)
SCIP_Bool SCIPsortedvecFindDownReal(SCIP_Real *realarray, SCIP_Real val, int len, int *pos)
void SCIPsortDownReal(SCIP_Real *realarray, int len)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
void SCIPsortDownInt(int *intarray, int len)
void SCIPsortInt(int *intarray, int len)
return SCIP_OKAY
static SCIP_SOL * sol
int r
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
SCIP_Real primsol
static SCIP_VAR ** vars
SCIP_Real alpha
interval arithmetics for provable bounds
static SCIP_Bool isIntegralScalar(SCIP_Real val, SCIP_Real scalar, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Real *intval)
Definition lp.c:5099
internal methods for LP management
SCIP_Bool SCIProwExactHasFpRelax(SCIP_ROWEXACT *row)
Definition lpexact.c:5089
SCIP_ROW * SCIProwExactGetRowRhs(SCIP_ROWEXACT *row)
Definition lpexact.c:5079
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:134
#define BMSmoveMemoryArray(ptr, source, num)
Definition memory.h:138
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition message.c:618
internal miscellaneous methods
#define MAXSCALE
#define MAXDELTA
#define MINDELTA
public methods for LP management
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebug(x)
Definition pub_message.h:93
#define SCIPdebugMessage
Definition pub_message.h:96
#define SCIPdebugPrintf
Definition pub_message.h:99
public data structures and miscellaneous methods
methods for selecting k-medians
methods for sorting joint arrays of various types
public methods for problem variables
wrapper for rational number arithmetic
public methods for certified solving
public methods for cuts and aggregation rows
public methods for exact solving
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 global and local (sub)problems
public methods for solutions
public methods for querying solving statistics
public methods for SCIP variables
SCIP_Real * M
Definition cuts.c:9160
SCIP_Real lambda
Definition cuts.c:9171
SCIP_Real * m
Definition cuts.c:9161
SCIP_Real d2
Definition cuts.c:9170
SCIP_Real mp
Definition cuts.c:9172
SCIP_Real ml
Definition cuts.c:9173
SCIP_Real d1
Definition cuts.c:9169
SCIP_VAR ** vars
Definition cuts.c:4114
int usevbds[NSECTIONS]
Definition cuts.c:4111
SCIP_Real QUAD(cutrhs)
SCIP_Bool isenfint[NSECTIONS]
Definition cuts.c:4107
int * cutinds
Definition cuts.c:4126
int nvars
Definition cuts.c:4115
int nbinimplvars
Definition cuts.c:4118
int nintvars
Definition cuts.c:4117
SCIP_Bool isimplint[NSECTIONS]
Definition cuts.c:4108
SCIP_Real * cutcoefs
Definition cuts.c:4123
int nintimplvars
Definition cuts.c:4119
int ncutinds
Definition cuts.c:4127
int totalnnz
Definition cuts.c:4103
int ncontvars
Definition cuts.c:4121
int ncontimplvars
Definition cuts.c:4120
int nbinvars
Definition cuts.c:4116
int * secindices[NSECTIONS]
Definition cuts.c:4104
int secnnz[NSECTIONS]
Definition cuts.c:4105
SCIP_Real * vals
Definition struct_cuts.h:44
SCIP_Real * rowweights
Definition struct_cuts.h:48
SCIP_Bool local
Definition struct_cuts.h:54
int * slacksign
Definition struct_cuts.h:47
SCIP_MIRINFO ** mirinfo
SCIP_AGGREGATIONINFO ** aggrinfo
SCIP_VAR * var
Definition struct_lp.h:162
int var_probindex
Definition struct_lp.h:180
SCIP_Real boundswitch
Definition struct_cuts.h:61
SCIP_Bool postprocess
Definition struct_cuts.h:68
SCIP_Real minfrac
Definition struct_cuts.h:62
SCIP_BOUNDTYPE * boundtypesfortrans
Definition struct_cuts.h:67
SCIP_Real maxfrac
Definition struct_cuts.h:63
SCIP_Bool allowlocal
Definition struct_cuts.h:69
SCIP_Real sup
SCIP_Real inf
SCIP_Real * slackscale
SCIP_Real * slackcoefficients
SCIP_RATIONAL * frac
SCIP_ROW ** slackrows
SCIP_Real * slackweight
SCIP_Bool * upperused
SCIP_Real * splitcoefficients
SCIP_RATIONAL * rhs
SCIP_Real * slackusedcoef
SCIP_Real unroundedrhs
SCIP_Bool * localbdused
SCIP_Bool * slackroundeddown
SCIP_INTERVAL * valsinterval
SCIP_Real rhs
Definition struct_lp.h:208
int lppos
Definition struct_lp.h:243
char * name
Definition struct_lp.h:229
SCIP_Real * vals
Definition struct_lp.h:232
unsigned int local
Definition struct_lp.h:264
SCIP_Real lhs
Definition struct_lp.h:207
SCIP_COL ** cols
Definition struct_lp.h:230
unsigned int integral
Definition struct_lp.h:263
SCIP_Real constant
Definition struct_lp.h:206
int * cols_index
Definition struct_lp.h:231
SCIP_Real * transbinvarsolvals
Definition cuts.c:9181
int * transvarcoefs
Definition cuts.c:9180
SCIP_Real * transcontvarsolvals
Definition cuts.c:9182
SCIP_Real * aggrcoefsbin
Definition cuts.c:9188
int * origcontvars
Definition cuts.c:9187
SCIP_Real transrhs
Definition cuts.c:9185
int * origbinvars
Definition cuts.c:9186
SCIP_Real * aggrconstants
Definition cuts.c:9192
SCIP_Real * aggrcoefscont
Definition cuts.c:9190
int ntransvars
Definition cuts.c:9184
SCIP_Real * transvarvubcoefs
Definition cuts.c:9183
data structures for certificate output
data structures for LP management
data structures for exact LP management
SCIP main data structure.
datastructures for global SCIP settings
type definitions for certificate output
struct SCIP_MirInfo SCIP_MIRINFO
struct SCIP_AggregationInfo SCIP_AGGREGATIONINFO
struct SCIP_CutGenParams SCIP_CUTGENPARAMS
Definition type_cuts.h:48
struct SCIP_AggrRow SCIP_AGGRROW
Definition type_cuts.h:37
#define SCIP_CUTGENMETHOD_KNAPSACKCOVER
Definition type_cuts.h:44
#define SCIP_CUTGENMETHOD_NONE
Definition type_cuts.h:42
struct SCIP_CutGenResult SCIP_CUTGENRESULT
Definition type_cuts.h:49
#define SCIP_CUTGENMETHOD_CMIR
Definition type_cuts.h:45
uint32_t SCIP_CUTGENMETHOD
Definition type_cuts.h:39
#define SCIP_CUTGENMETHOD_FLOWCOVER
Definition type_cuts.h:43
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition type_lp.h:57
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:60
struct SCIP_RowExact SCIP_ROWEXACT
@ SCIP_BASESTAT_UPPER
Definition type_lpi.h:93
@ SCIP_BASESTAT_LOWER
Definition type_lpi.h:91
enum SCIP_BaseStat SCIP_BASESTAT
Definition type_lpi.h:96
struct SCIP_Messagehdlr SCIP_MESSAGEHDLR
#define SCIP_DECL_SORTINDCOMP(x)
Definition type_misc.h:181
struct SCIP_Rational SCIP_RATIONAL
@ SCIP_R_ROUND_UPWARDS
@ SCIP_R_ROUND_DOWNWARDS
@ SCIP_INVALIDCALL
@ SCIP_ERROR
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARTYPE_INTEGER
Definition type_var.h:65
@ SCIP_VARTYPE_CONTINUOUS
Definition type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64