Scippy

SCIP

Solving Constraint Integer Programs

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-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file 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/* =========================================== general static functions =========================================== */
68#ifdef SCIP_DEBUG
69static
70void printCutQuad(
71 SCIP* scip, /**< SCIP data structure */
72 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
73 SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
74 QUAD(SCIP_Real cutrhs), /**< right hand side of the MIR row */
75 int* cutinds, /**< indices of problem variables for non-zero coefficients */
76 int cutnnz, /**< number of non-zeros in cut */
77 SCIP_Bool ignoresol,
78 SCIP_Bool islocal
79 )
80{
81 SCIP_Real QUAD(activity);
82 SCIP_VAR** vars;
83
84 assert(scip != NULL);
85 vars = SCIPgetVars(scip);
86
87 SCIPdebugMsg(scip, "CUT:");
88 QUAD_ASSIGN(activity, 0.0);
89
90 /**! [SnippetCodeStyleInLoopDeclaration] */
91 for( int i = 0; i < cutnnz; ++i )
92 {
93 SCIP_Real QUAD(coef);
94
95 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
96
97 if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_BINARY )
98 SCIPdebugMsgPrint(scip, " %+g<%s>[B]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
99 else if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_INTEGER )
100 SCIPdebugMsgPrint(scip, " %+g<%s>[I]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
101 else
102 SCIPdebugMsgPrint(scip, " %+g<%s>[C]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
103
104 if( ! ignoresol )
105 {
106 SCIPquadprecProdQD(coef, coef, (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]])));
107 }
108 else
109 {
110 if( cutcoefs[i] > 0.0 )
111 {
112 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]])));
113 }
114 else
115 {
116 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]])));
117 }
118 }
119
120 SCIPquadprecSumQQ(activity, activity, coef);
121 }
122 /**! [SnippetCodeStyleInLoopDeclaration] */
123 SCIPdebugMsgPrint(scip, " <= %.6f (activity: %g)\n", QUAD_TO_DBL(cutrhs), QUAD_TO_DBL(activity));
124}
125
126static
127void printCut(
128 SCIP* scip, /**< SCIP data structure */
129 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
130 SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
131 SCIP_Real cutrhs, /**< right hand side of the MIR row */
132 int* cutinds, /**< indices of problem variables for non-zero coefficients */
133 int cutnnz, /**< number of non-zeros in cut */
134 SCIP_Bool ignoresol,
135 SCIP_Bool islocal
136 )
137{
138 SCIP_Real activity;
139 SCIP_VAR** vars;
140 int i;
141
142 assert(scip != NULL);
143 vars = SCIPgetVars(scip);
144
145 SCIPdebugMsg(scip, "CUT:");
146 activity = 0.0;
147 for( i = 0; i < cutnnz; ++i )
148 {
149 SCIP_Real coef;
150
151 coef = cutcoefs[cutinds[i]];
152
153 if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_BINARY )
154 SCIPdebugMsgPrint(scip, " %+g<%s>[B]", coef, SCIPvarGetName(vars[cutinds[i]]));
155 else if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_INTEGER )
156 SCIPdebugMsgPrint(scip, " %+g<%s>[I]", coef, SCIPvarGetName(vars[cutinds[i]]));
157 else
158 SCIPdebugMsgPrint(scip, " %+g<%s>[C]", coef, SCIPvarGetName(vars[cutinds[i]]));
159
160 if( ! ignoresol )
161 {
162 coef = coef * (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]]));
163 }
164 else
165 {
166 if( cutcoefs[i] > 0.0 )
167 {
168 coef = coef * (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]));
169 }
170 else
171 {
172 coef = coef * (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
173 }
174 }
175
176 activity += coef;
177 }
178 SCIPdebugMsgPrint(scip, " <= %.6f (activity: %g)\n", cutrhs, activity);
179}
180#endif
181
182/** macro to make sure a value is not equal to zero, i.e. NONZERO(x) != 0.0
183 * will be TRUE for every x including 0.0
184 *
185 * To avoid branches it will add 1e-100 with the same sign as x to x which will
186 * be rounded away for any sane non-zero value but will make sure the value is
187 * never exactly 0.0.
188 */
189#define NONZERO(x) (COPYSIGN(1e-100, (x)) + (x))
190
191/** add a scaled row to a dense vector indexed over the problem variables and keep the
192 * index of non-zeros up-to-date
193 */
194static
196 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
197 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
198 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
199 SCIP_ROW* row, /**< row coefficients to add to variable vector */
200 SCIP_Real scale /**< scale for adding given row to variable vector */
201 )
202{
203 int i;
204
205 assert(inds != NULL);
206 assert(vals != NULL);
207 assert(nnz != NULL);
208 assert(row != NULL);
209
210 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
211 for( i = 0 ; i < row->len; ++i )
212 {
213 SCIP_Real val;
214 int probindex;
215
216 probindex = row->cols[i]->var_probindex;
217 val = vals[probindex];
218
219 if( val == 0.0 )
220 inds[(*nnz)++] = probindex;
221
222 val += row->vals[i] * scale;
223
224 /* the value must not be exactly zero due to sparsity pattern */
225 val = NONZERO(val);
226
227 assert(val != 0.0);
228 vals[probindex] = val;
229 }
230
231 return SCIP_OKAY;
232}
233
234/** add a scaled row to a dense vector indexed over the problem variables and keep the
235 * index of non-zeros up-to-date
236 *
237 * This is the quad precision version of varVecAddScaledRowCoefs().
238 */
239static
241 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
242 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
243 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
244 SCIP_ROW* row, /**< row coefficients to add to variable vector */
245 SCIP_Real scale /**< scale for adding given row to variable vector */
246 )
247{
248 int i;
249
250 assert(inds != NULL);
251 assert(vals != NULL);
252 assert(nnz != NULL);
253 assert(row != NULL);
254
255 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
256 for( i = 0 ; i < row->len; ++i )
257 {
258 SCIP_Real QUAD(scaledrowval);
259 SCIP_Real QUAD(val);
260 int probindex;
261
262 probindex = row->cols[i]->var_probindex;
263 QUAD_ARRAY_LOAD(val, vals, probindex);
264
265 if( QUAD_HI(val) == 0.0 )
266 inds[(*nnz)++] = probindex;
267
268 SCIPquadprecProdDD(scaledrowval, row->vals[i], scale);
269 SCIPquadprecSumQQ(val, val, scaledrowval);
270
271 /* the value must not be exactly zero due to sparsity pattern */
272 QUAD_HI(val) = NONZERO(QUAD_HI(val));
273 assert(QUAD_HI(val) != 0.0);
274
275 QUAD_ARRAY_STORE(vals, probindex, val);
276 }
277
278 return SCIP_OKAY;
279}
280
281/** add a scaled row to a dense vector indexed over the problem variables and keep the
282 * index of non-zeros up-to-date
283 *
284 * This is the quad precision version of varVecAddScaledRowCoefs() with a quad precision scaling factor.
285 */
286static
288 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
289 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
290 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
291 SCIP_ROW* row, /**< row coefficients to add to variable vector */
292 QUAD(SCIP_Real scale) /**< scale for adding given row to variable vector */
293 )
294{
295 int i;
296
297 assert(inds != NULL);
298 assert(vals != NULL);
299 assert(nnz != NULL);
300 assert(row != NULL);
301
302 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
303 for( i = 0 ; i < row->len; ++i )
304 {
305 SCIP_Real QUAD(val);
306 SCIP_Real QUAD(rowval);
307 int probindex;
308
309 probindex = row->cols[i]->var_probindex;
310 QUAD_ARRAY_LOAD(val, vals, probindex);
311
312 if( QUAD_HI(val) == 0.0 )
313 {
314 inds[(*nnz)++] = probindex;
315 SCIPquadprecProdQD(val, scale, row->vals[i]);
316 }
317 else
318 {
319 SCIPquadprecProdQD(rowval, scale, row->vals[i]);
320 SCIPquadprecSumQQ(val, val, rowval);
321 }
322
323 /* the value must not be exactly zero due to sparsity pattern */
324 QUAD_HI(val) = NONZERO(QUAD_HI(val));
325 assert(QUAD_HI(val) != 0.0);
326
327 QUAD_ARRAY_STORE(vals, probindex, val);
328 }
329
330 return SCIP_OKAY;
331}
332
333/** add a scaled row to a dense vector indexed over the problem variables and keep the index of non-zeros up-to-date
334 *
335 * In the safe variant, we need to transform all variables (implicitly) to nonnegative variables using their
336 * upper/lower bounds. When adding \f$\lambda * (c^Tx \le d)\f$ to \f$a^Tx \le b\f$, this results in:
337 *
338 * \f{align*}{
339 * m_i & =a_i+\lambda c_i \\
340 * U \cap L & = \emptyset \\
341 * U & = \{ i : x_i \le u_i\} \\
342 * L & = \{ i : x_i \ge l_i\} \\
343 * \sum_{i \in U} \overline{m_i}x_i + \sum_{i \in L}\underline{m_i}x_i
344 * & \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
345 * \f}
346 *
347 * This methods sums up the left hand side, and stores the change of the rhs due to the variable bounds in rhschange.
348 *
349 * @note this method is safe for usage in exact solving mode
350 */
351static
353 SCIP* scip, /**< scip data structure */
354 int* inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
355 SCIP_Real* vals, /**< array with values of variable vector */
356 int* nnz, /**< number of non-zeros coefficients of variable vector */
357 SCIP_ROW* row, /**< row coefficients to add to variable vector */
358 SCIP_Real scale, /**< scale for adding given row to variable vector */
359 SCIP_Real* rhschange, /**< change in rhs due to variable conjugation */
360 SCIP_Bool* success /**< was the addition successful? */
361 )
362{
363 int i;
364 SCIP_ROUNDMODE previousroundmode;
365 SCIP_VAR* var;
366 SCIP_ROWEXACT* rowexact;
367
368 assert(SCIPisExact(scip));
369 assert(inds != NULL);
370 assert(vals != NULL);
371 assert(nnz != NULL);
372 assert(row != NULL);
373 assert(rhschange != NULL);
374 assert(success != NULL);
375 assert(*success);
376
377 previousroundmode = SCIPintervalGetRoundingMode();
379
380 *rhschange = 0;
381 rowexact = SCIProwGetRowExact(row);
382
383 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
384 for( i = 0 ; i < row->len; ++i )
385 {
386 SCIP_Real val;
387 SCIP_INTERVAL valinterval;
388 int probindex;
389
390 probindex = row->cols[i]->var_probindex;
391 var = row->cols[i]->var;
392 val = vals[probindex];
393
394 if( val == 0.0 )
395 {
396 assert(*nnz < SCIPgetNVars(scip));
397 inds[(*nnz)++] = probindex;
398 }
399
400 if( val == SCIP_INVALID ) /*lint !e777*/
401 val = 0.0;
402
403 SCIPintervalSetBounds(&valinterval, rowexact->valsinterval[i].inf, rowexact->valsinterval[i].sup);
404 SCIPintervalMulScalar(SCIPinfinity(scip), &valinterval, valinterval, scale);
405 SCIPintervalAddScalar(SCIPinfinity(scip), &valinterval, valinterval, val);
406
407 if( SCIPisInfinity(scip, REALABS(valinterval.inf)) || SCIPisInfinity(scip, REALABS(valinterval.sup)) )
408 {
409 *success = FALSE;
410 SCIPintervalSetRoundingMode(previousroundmode);
411 return SCIP_OKAY;
412 }
413
414 if( SCIPvarGetLbGlobal(var) > -SCIPinfinity(scip) && SCIPvarGetLbGlobal(var) >= 0 )
415 val = valinterval.inf;
416 else if(SCIPvarGetUbGlobal(var) < SCIPinfinity(scip) && SCIPvarGetUbGlobal(var) <= 0 )
417 val = valinterval.sup;
418 else if( SCIPvarGetLbGlobal(var) > -SCIPinfinity(scip) )
419 {
420 val = valinterval.inf;
422 *rhschange += (valinterval.sup - valinterval.inf) * (-SCIPvarGetLbGlobal(var));
423 }
424 else if( SCIPvarGetUbGlobal(var) < SCIPinfinity(scip) )
425 {
426 val = valinterval.sup;
428 *rhschange += (valinterval.sup - valinterval.inf) * (SCIPvarGetUbGlobal(var));
429 }
430 else
431 {
432 *success = FALSE;
433 SCIPintervalSetRoundingMode(previousroundmode);
434 return SCIP_OKAY;
435 }
436
437 /* 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
438 * exactly; this is taken care of in removeZerosSafely */
439 if( val == 0.0 )
440 val = SCIP_INVALID;
441
442 vals[probindex] = val;
443 }
444
445 SCIPintervalSetRoundingMode(previousroundmode);
446
447 return SCIP_OKAY;
448}
449
450/** calculates the cut efficacy for the given solution */
451static
453 SCIP* scip, /**< SCIP data structure */
454 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
455 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
456 SCIP_Real cutrhs, /**< the right hand side of the cut */
457 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
458 int cutnnz /**< the number of non-zeros in the cut */
459 )
460{
461 SCIP_VAR** vars;
462 SCIP_Real norm = 0.0;
463 SCIP_Real activity = 0.0;
464 int i;
465
466 assert(scip != NULL);
467 assert(cutcoefs != NULL);
468 assert(cutinds != NULL);
469
470 vars = SCIPgetVars(scip);
471
472 switch( scip->set->sepa_efficacynorm )
473 {
474 case 'e':
475 for( i = 0; i < cutnnz; ++i )
476 {
477 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
478 norm += SQR(cutcoefs[i]);
479 }
480 norm = sqrt(norm);
481 break;
482 case 'm':
483 for( i = 0; i < cutnnz; ++i )
484 {
485 SCIP_Real absval;
486
487 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
488 absval = REALABS(cutcoefs[i]);
489 norm = MAX(norm, absval);
490 }
491 break;
492 case 's':
493 for( i = 0; i < cutnnz; ++i )
494 {
495 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
496 norm += REALABS(cutcoefs[i]);
497 }
498 break;
499 case 'd':
500 for( i = 0; i < cutnnz; ++i )
501 {
502 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
503 if( !SCIPisZero(scip, cutcoefs[i]) )
504 norm = 1.0;
505 }
506 break;
507 default:
508 SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", scip->set->sepa_efficacynorm);
509 assert(FALSE); /*lint !e506*/
510 }
511
512 return (activity - cutrhs) / MAX(1e-6, norm);
513}
514
515/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter */
516static
518 SCIP* scip, /**< SCIP data structure */
519 SCIP_Real* vals, /**< array of the non-zero coefficients in the vector; this is a quad precision array! */
520 int* inds, /**< array of the problem indices of variables with a non-zero coefficient in the vector */
521 int nnz /**< the number of non-zeros in the vector */
522 )
523{
524 SCIP_Real norm = 0.0;
525 SCIP_Real QUAD(coef);
526 int i;
527
528 assert(scip != NULL);
529 assert(scip->set != NULL);
530
531 switch( scip->set->sepa_efficacynorm )
532 {
533 case 'e':
534 for( i = 0; i < nnz; ++i )
535 {
536 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
537 norm += SQR(QUAD_TO_DBL(coef));
538 }
539 norm = sqrt(norm);
540 break;
541 case 'm':
542 for( i = 0; i < nnz; ++i )
543 {
544 SCIP_Real absval;
545 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
546
547 absval = REALABS(QUAD_TO_DBL(coef));
548 norm = MAX(norm, absval);
549 }
550 break;
551 case 's':
552 for( i = 0; i < nnz; ++i )
553 {
554 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
555 norm += REALABS(QUAD_TO_DBL(coef));
556 }
557 break;
558 case 'd':
559 for( i = 0; i < nnz; ++i )
560 {
561 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
562 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
563 {
564 norm = 1.0;
565 break;
566 }
567 }
568 break;
569 default:
570 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
571 assert(FALSE); /*lint !e506*/
572 }
573
574 return norm;
575}
576
577/** calculates the cut efficacy for the given solution; the cut coefs are stored densely */
578static
580 SCIP* scip, /**< SCIP data structure */
581 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
582 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
583 SCIP_Real cutrhs, /**< the right hand side of the cut */
584 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
585 int cutnnz /**< the number of non-zeros in the cut */
586 )
587{
588 SCIP_VAR** vars;
589 SCIP_Real norm = 0.0;
590 SCIP_Real activity = 0.0;
591 SCIP_Real coef;
592 int i;
593
594 assert(scip != NULL);
595 assert(cutcoefs != NULL);
596 assert(cutinds != NULL);
597 assert(scip->set != NULL);
598
599 vars = SCIPgetVars(scip);
600
601 switch( scip->set->sepa_efficacynorm )
602 {
603 case 'e':
604 for( i = 0; i < cutnnz; ++i )
605 {
606 coef = cutcoefs[cutinds[i]];
607 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
608 norm += SQR(coef);
609 }
610 norm = SQR(norm);
611 break;
612 case 'm':
613 for( i = 0; i < cutnnz; ++i )
614 {
615 SCIP_Real absval;
616
617 coef = cutcoefs[cutinds[i]];
618 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
619 absval = REALABS(coef);
620 norm = MAX(norm, absval);
621 }
622 break;
623 case 's':
624 for( i = 0; i < cutnnz; ++i )
625 {
626 coef = cutcoefs[cutinds[i]];
627 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
628 norm += REALABS(coef);
629 }
630 break;
631 case 'd':
632 for( i = 0; i < cutnnz; ++i )
633 {
634 coef = cutcoefs[cutinds[i]];
635 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
636 if( !SCIPisZero(scip, coef) )
637 norm = 1.0;
638 }
639 break;
640 default:
641 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
642 assert(FALSE); /*lint !e506*/
643 }
644
645 return (activity - cutrhs) / MAX(1e-6, norm);
646}
647
648/** calculates the cut efficacy for the given solution; the cut coefs are stored densely and in quad precision */
649static
651 SCIP* scip, /**< SCIP data structure */
652 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
653 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
654 SCIP_Real cutrhs, /**< the right hand side of the cut */
655 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
656 int cutnnz /**< the number of non-zeros in the cut */
657 )
658{
659 SCIP_VAR** vars;
660 SCIP_Real norm = 0.0;
661 SCIP_Real activity = 0.0;
662 SCIP_Real QUAD(coef);
663 int i;
664
665 assert(scip != NULL);
666 assert(cutcoefs != NULL);
667 assert(cutinds != NULL);
668 assert(scip->set != NULL);
669
670 vars = SCIPgetVars(scip);
671
672 switch( scip->set->sepa_efficacynorm )
673 {
674 case 'e':
675 for( i = 0; i < cutnnz; ++i )
676 {
677 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
678 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
679 norm += SQR(QUAD_TO_DBL(coef));
680 }
681 norm = sqrt(norm);
682 break;
683 case 'm':
684 for( i = 0; i < cutnnz; ++i )
685 {
686 SCIP_Real absval;
687
688 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
689 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
690 absval = REALABS(QUAD_TO_DBL(coef));
691 norm = MAX(norm, absval);
692 }
693 break;
694 case 's':
695 for( i = 0; i < cutnnz; ++i )
696 {
697 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
698 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
699 norm += REALABS(QUAD_TO_DBL(coef));
700 }
701 break;
702 case 'd':
703 for( i = 0; i < cutnnz; ++i )
704 {
705 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
706 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
707 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
708 norm = 1.0;
709 }
710 break;
711 default:
712 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
713 assert(FALSE); /*lint !e506*/
714 }
715
716 return (activity - cutrhs) / MAX(1e-6, norm);
717}
718
719/** safely (in the exact solving mode sense) remove all items with |a_i| or |u_i - l_i)| below the given value
720 *
721 * Returns TRUE if the cut became redundant.
722 * If it is a local cut, use local bounds, otherwise, use global bounds.
723 *
724 * * @note this method is safe for usage in exact solving mode
725 */
726static
728 SCIP* scip, /**< SCIP data structure */
729 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
730 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
731 SCIP_Real* cutrhs, /**< the right hand side of the cut */
732 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
733 int* cutnnz /**< the number of non-zeros in the cut */
734 )
735{
736 int i;
737 SCIP_VAR** vars;
738 SCIP_ROUNDMODE previousroundmode;
739
740 assert(SCIPisExact(scip));
741
742 previousroundmode = SCIPintervalGetRoundingMode();
744
745 vars = SCIPgetVars(scip);
746
747 for( i = 0; i < *cutnnz; )
748 {
749 SCIP_Real val;
750 SCIP_Real lb;
751 SCIP_Real ub;
752 int v;
753 SCIP_Bool isfixed;
754
755 v = cutinds[i];
756 val = cutcoefs[v];
757
758 if( val == SCIP_INVALID ) /*lint !e777*/
759 val = 0.0;
760
761 /* for now we always use global bounds in exact solving mode (could be improved for local cuts in the future) */
762 lb = SCIPvarGetLbGlobal(vars[v]);
763 ub = SCIPvarGetUbGlobal(vars[v]);
764
765 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
766 isfixed = TRUE;
767 else
768 isfixed = FALSE;
769
770 if( EPSZ(val, minval) || isfixed )
771 {
772 /* adjust left and right hand sides with max contribution */
773 if( val < 0.0 )
774 {
775 if( SCIPisInfinity(scip, ub) )
776 {
777 SCIPintervalSetRoundingMode(previousroundmode);
778 return TRUE;
779 }
780 else
781 *cutrhs += (-val) * ub;
782 }
783 else
784 {
785 if( SCIPisInfinity(scip, -lb) )
786 {
787 SCIPintervalSetRoundingMode(previousroundmode);
788 return TRUE;
789 }
790 else
791 *cutrhs += (-val) * lb;
792 }
793
794 val = 0.0;
795 cutcoefs[v] = val;
796
797 /* remove non-zero entry */
798 --(*cutnnz);
799 cutinds[i] = cutinds[*cutnnz];
800 }
801 else
802 ++i;
803 }
804
805 /* relax rhs to 0, if it's very close to 0 */
806 if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
807 *cutrhs = 0.0;
808
809 SCIPintervalSetRoundingMode(previousroundmode);
810
811 return FALSE;
812}
813
814/** safely remove all items with |a_i| or |u_i - l_i)| below the given value
815 *
816 * Returns TRUE if the cut became redundant.
817 * If it is a local cut, use local bounds, otherwise, use global bounds.
818 *
819 * @note this method is safe for usage in exact solving mode
820 */
821static
823 SCIP* scip, /**< SCIP data structure */
824 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
825 SCIP_Bool cutislocal, /**< is the cut local? */
826 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
827 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
828 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
829 int* cutnnz /**< the number of non-zeros in the cut */
830 )
831{
832 int i;
833 SCIP_VAR** vars;
834
835 vars = SCIPgetVars(scip);
836
837 for( i = 0; i < *cutnnz; )
838 {
839 SCIP_Real QUAD(val);
840 SCIP_Real lb;
841 SCIP_Real ub;
842 int v;
843 SCIP_Bool isfixed;
844
845 v = cutinds[i];
846 QUAD_ARRAY_LOAD(val, cutcoefs, v);
847
848 if( cutislocal )
849 {
850 lb = SCIPvarGetLbLocal(vars[v]);
851 ub = SCIPvarGetUbLocal(vars[v]);
852 }
853 else
854 {
855 lb = SCIPvarGetLbGlobal(vars[v]);
856 ub = SCIPvarGetUbGlobal(vars[v]);
857 }
858
859 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
860 isfixed = TRUE;
861 else
862 isfixed = FALSE;
863
864 if( isfixed || EPSZ(QUAD_TO_DBL(val), minval) )
865 {
866 if( REALABS(QUAD_TO_DBL(val)) > QUAD_EPSILON )
867 {
868 /* adjust right hand side with max contribution */
869 if( QUAD_TO_DBL(val) < 0.0 )
870 {
871 if( SCIPisInfinity(scip, ub) )
872 return TRUE;
873 else
874 {
875 SCIPquadprecProdQD(val, val, ub);
876 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
877 }
878 }
879 else
880 {
881 if( SCIPisInfinity(scip, -lb) )
882 return TRUE;
883 else
884 {
885 SCIPquadprecProdQD(val, val, lb);
886 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
887 }
888 }
889 }
890
891 QUAD_ASSIGN(val, 0.0);
892 QUAD_ARRAY_STORE(cutcoefs, v, val);
893
894 /* remove non-zero entry */
895 --(*cutnnz);
896 cutinds[i] = cutinds[*cutnnz];
897 }
898 else
899 ++i;
900 }
901
902 /* relax rhs to 0, if it's very close to 0 */
903 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
904 QUAD_ASSIGN(*cutrhs, 0.0);
905
906 return FALSE;
907}
908
909/** safely remove all items with |a_i| or |u_i - l_i| below the given value
910 *
911 * Returns TRUE if the cut became redundant.
912 * If it is a local cut, use local bounds, otherwise, use global bounds.
913 */
914static
916 SCIP* scip, /**< SCIP data structure */
917 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
918 SCIP_Bool cutislocal, /**< is the cut local? */
919 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
920 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
921 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
922 int* cutnnz /**< the number of non-zeros in the cut */
923 )
924{
925 int i;
926 SCIP_VAR** vars;
927
928 vars = SCIPgetVars(scip);
929
930 /* loop over non-zeros and remove values below minval; values above QUAD_EPSILON are cancelled with their bound
931 * to avoid numerical rounding errors
932 */
933 for( i = 0; i < *cutnnz; )
934 {
935 SCIP_Real val;
936 SCIP_Real lb;
937 SCIP_Real ub;
938 int v;
939 SCIP_Bool isfixed;
940 SCIP_Real QUAD(quadprod);
941
942 v = cutinds[i];
943 val = cutcoefs[v];
944
945 if( cutislocal )
946 {
947 lb = SCIPvarGetLbLocal(vars[v]);
948 ub = SCIPvarGetUbLocal(vars[v]);
949 }
950 else
951 {
952 lb = SCIPvarGetLbGlobal(vars[v]);
953 ub = SCIPvarGetUbGlobal(vars[v]);
954 }
955
956 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
957 isfixed = TRUE;
958 else
959 isfixed = FALSE;
960
961 if( EPSZ(val, minval) || isfixed )
962 {
963 if( REALABS(val) > QUAD_EPSILON )
964 {
965 /* adjust left and right hand sides with max contribution */
966 if( val < 0.0 )
967 {
968 if( SCIPisInfinity(scip, ub) )
969 return TRUE;
970 else
971 {
972 SCIPquadprecProdDD(quadprod, -val, ub);
973 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
974 }
975 }
976 else
977 {
978 if( SCIPisInfinity(scip, -lb) )
979 return TRUE;
980 else
981 {
982 SCIPquadprecProdDD(quadprod, -val, lb);
983 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
984 }
985 }
986 }
987
988 cutcoefs[v] = 0.0;
989
990 /* remove non-zero entry */
991 --(*cutnnz);
992 cutinds[i] = cutinds[*cutnnz];
993 }
994 else
995 ++i;
996 }
997
998 /* relax rhs to 0, if it's very close to 0 */
999 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
1000 QUAD_ASSIGN(*cutrhs, 0.0);
1001
1002 return FALSE;
1003}
1004
1005/** compare absolute values of coefficients in quad precision */
1006static
1007SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
1008{
1009 SCIP_Real abscoef1;
1010 SCIP_Real abscoef2;
1011 SCIP_Real QUAD(coef1);
1012 SCIP_Real QUAD(coef2);
1013 SCIP_Real* coefs = (SCIP_Real*) dataptr;
1014
1015 QUAD_ARRAY_LOAD(coef1, coefs, ind1);
1016 QUAD_ARRAY_LOAD(coef2, coefs, ind2);
1017
1018 abscoef1 = REALABS(QUAD_TO_DBL(coef1));
1019 abscoef2 = REALABS(QUAD_TO_DBL(coef2));
1020
1021 if( abscoef1 < abscoef2 )
1022 return -1;
1023 if( abscoef2 < abscoef1 )
1024 return 1;
1025
1026 return 0;
1027}
1028
1029/** compare absolute values of coefficients */
1030static
1032{
1033 SCIP_Real abscoef1;
1034 SCIP_Real abscoef2;
1035 SCIP_Real* coefs = (SCIP_Real*) dataptr;
1036
1037 abscoef1 = REALABS(coefs[ind1]);
1038 abscoef2 = REALABS(coefs[ind2]);
1039
1040 if( abscoef1 < abscoef2 )
1041 return -1;
1042 if( abscoef2 < abscoef1 )
1043 return 1;
1044
1045 return 0;
1046}
1047
1048/** change given coefficient to new given value, adjust right hand side using the variables bound;
1049 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
1050 */
1051static
1053 SCIP* scip, /**< SCIP data structure */
1054 SCIP_VAR* var, /**< variable the coefficient belongs to */
1055 SCIP_Real oldcoeff, /**< old coefficient value */
1056 SCIP_Real newcoeff, /**< new coefficient value */
1057 SCIP_Bool cutislocal, /**< is the cut local? */
1058 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
1059 )
1060{
1061 SCIP_Real QUAD(delta);
1062
1063 SCIPquadprecSumDD(delta, newcoeff, -oldcoeff);
1064
1065 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
1066 {
1067 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
1068
1069 if( SCIPisInfinity(scip, ub) )
1070 return TRUE;
1071 else
1072 {
1073 SCIPquadprecProdQD(delta, delta, ub);
1074 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
1075 }
1076 }
1077 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
1078 {
1079 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
1080
1081 if( SCIPisInfinity(scip, -lb) )
1082 return TRUE;
1083 else
1084 {
1085 SCIPquadprecProdQD(delta, delta, lb);
1086 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
1087 }
1088 }
1089
1090 return FALSE;
1091}
1092
1093/** change given (quad) coefficient to new given value, adjust right hand side using the variables bound;
1094 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
1095 */
1096static
1098 SCIP* scip, /**< SCIP data structure */
1099 SCIP_VAR* var, /**< variable the coefficient belongs to */
1100 QUAD(SCIP_Real oldcoeff), /**< old coefficient value */
1101 SCIP_Real newcoeff, /**< new coefficient value */
1102 SCIP_Bool cutislocal, /**< is the cut local? */
1103 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
1104 )
1105{
1106 SCIP_Real QUAD(delta);
1107
1108 SCIPquadprecSumQD(delta, -oldcoeff, newcoeff);
1109
1110 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
1111 {
1112 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
1113
1114 if( SCIPisInfinity(scip, ub) )
1115 return TRUE;
1116 else
1117 {
1118 SCIPquadprecProdQD(delta, delta, ub);
1119 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
1120 }
1121 }
1122 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
1123 {
1124 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
1125
1126 if( SCIPisInfinity(scip, -lb) )
1127 return TRUE;
1128 else
1129 {
1130 SCIPquadprecProdQD(delta, delta, lb);
1131 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
1132 }
1133 }
1134
1135 return FALSE;
1136}
1137
1138/** change given coefficient to new given value, adjust right hand side using the variables bound;
1139 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
1140 */
1141static
1143 SCIP* scip, /**< SCIP data structure */
1144 SCIP_VAR* var, /**< variable the coefficient belongs to */
1145 SCIP_Real oldcoeff, /**< old coefficient value */
1146 SCIP_Real newcoeff, /**< new coefficient value */
1147 SCIP_Bool cutislocal, /**< is the cut local? */
1148 SCIP_Real* cutrhs /**< pointer to adjust right hand side of cut */
1149 )
1150{
1151 SCIP_INTERVAL delta;
1152 SCIP_ROUNDMODE previousroundmode;
1153
1154 assert(SCIPisExact(scip));
1155
1156 previousroundmode = SCIPintervalGetRoundingMode();
1158
1159 SCIPintervalSet(&delta, newcoeff);
1160 SCIPintervalSubScalar(SCIPinfinity(scip), &delta, delta, oldcoeff);
1161
1162 if( SCIPintervalGetSup(delta) > 0 )
1163 {
1164 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
1165
1166 if( SCIPisInfinity(scip, ub) )
1167 {
1168 SCIPintervalSetRoundingMode(previousroundmode);
1169 return TRUE;
1170 }
1171 else
1172 {
1173 SCIPintervalMulScalar(SCIPinfinity(scip), &delta, delta, ub);
1174 *cutrhs += SCIPintervalGetSup(delta);
1175 }
1176 }
1177 else if( SCIPintervalGetInf(delta) < 0 )
1178 {
1179 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
1180
1181 if( SCIPisInfinity(scip, -lb) )
1182 {
1183 SCIPintervalSetRoundingMode(previousroundmode);
1184 return TRUE;
1185 }
1186 else
1187 {
1188 SCIPintervalMulScalar(SCIPinfinity(scip), &delta, delta, lb);
1189 *cutrhs += SCIPintervalGetSup(delta);
1190 }
1191 }
1192 else
1193 {
1194 return TRUE;
1195 }
1196
1197 return FALSE;
1198}
1199
1200
1201/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
1202 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse quad precision array;
1203 *
1204 * This is the quad precision version of cutTightenCoefs() below.
1205 */
1206static
1208 SCIP* scip, /**< SCIP data structure */
1209 SCIP_Bool cutislocal, /**< is the cut local? */
1210 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1211 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
1212 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1213 int* cutnnz, /**< the number of non-zeros in the cut */
1214 SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
1215 )
1216{
1217 int i;
1218 int nintegralvars;
1219 SCIP_Bool isintegral = TRUE;
1220 SCIP_VAR** vars;
1221 SCIP_Real QUAD(maxacttmp);
1222 SCIP_Real maxact;
1223 SCIP_Real maxabsintval = 0.0;
1224 SCIP_Real maxabscontval = 0.0;
1225
1226 QUAD_ASSIGN(maxacttmp, 0.0);
1227
1228 vars = SCIPgetVars(scip);
1229 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1230
1231 assert(redundant != NULL);
1232 *redundant = FALSE;
1233
1234 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
1235 for( i = 0; i < *cutnnz; ++i )
1236 {
1237 SCIP_Real QUAD(val);
1238
1239 assert(cutinds[i] >= 0);
1240 assert(vars[cutinds[i]] != NULL);
1241
1242 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1243
1244 if( QUAD_TO_DBL(val) < 0.0 )
1245 {
1246 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1247
1248 if( SCIPisInfinity(scip, -lb) )
1249 return SCIP_OKAY;
1250
1251 if( cutinds[i] < nintegralvars )
1252 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
1253 else
1254 {
1255 maxabscontval = MAX(maxabscontval, -QUAD_TO_DBL(val));
1256 isintegral = FALSE;
1257 }
1258
1259 SCIPquadprecProdQD(val, val, lb);
1260 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
1261 }
1262 else
1263 {
1264 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1265
1266 if( SCIPisInfinity(scip, ub) )
1267 return SCIP_OKAY;
1268
1269 if( cutinds[i] < nintegralvars )
1270 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
1271 else
1272 {
1273 maxabscontval = MAX(maxabscontval, QUAD_TO_DBL(val));
1274 isintegral = FALSE;
1275 }
1276
1277 SCIPquadprecProdQD(val, val, ub);
1278 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
1279 }
1280 }
1281
1282 maxact = QUAD_TO_DBL(maxacttmp);
1283
1284 /* cut is redundant in activity bounds */
1285 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1286 {
1287 *redundant = TRUE;
1288 return SCIP_OKAY;
1289 }
1290
1291 /* cut is only on integral variables, try to scale to integral coefficients */
1292 if( isintegral )
1293 {
1294 SCIP_Real equiscale;
1295 SCIP_Real intscalar;
1296 SCIP_Bool success;
1297 SCIP_Real* intcoeffs;
1298
1299 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
1300
1301 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
1302
1303 for( i = 0; i < *cutnnz; ++i )
1304 {
1305 SCIP_Real QUAD(val);
1306
1307 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1308 SCIPquadprecProdQD(val, val, equiscale);
1309
1310 intcoeffs[i] = QUAD_TO_DBL(val);
1311 }
1312
1314 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
1315
1316 SCIPfreeBufferArray(scip, &intcoeffs);
1317
1318 if( success )
1319 {
1320 /* if successful, apply the scaling */
1321 intscalar *= equiscale;
1322 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
1323
1324 for( i = 0; i < *cutnnz; )
1325 {
1326 SCIP_Real QUAD(val);
1327 SCIP_Real intval;
1328
1329 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1330 SCIPquadprecProdQD(val, val, intscalar);
1331
1332 intval = SCIPround(scip, QUAD_TO_DBL(val));
1333
1334 if( chgQuadCoeffWithBound(scip, vars[cutinds[i]], QUAD(val), intval, cutislocal, QUAD(cutrhs)) )
1335 {
1336 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
1337 *redundant = TRUE;
1338 return SCIP_OKAY;
1339 }
1340
1341 if( intval != 0.0 )
1342 {
1343 QUAD_ASSIGN(val, intval);
1344 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1345 ++i;
1346 }
1347 else
1348 {
1349 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
1350 QUAD_ASSIGN(val, 0.0);
1351 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1352 --(*cutnnz);
1353 cutinds[i] = cutinds[*cutnnz];
1354 }
1355 }
1356
1357 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
1358
1359 /* recompute the maximal activity after scaling to integral values */
1360 QUAD_ASSIGN(maxacttmp, 0.0);
1361 maxabsintval = 0.0;
1362
1363 for( i = 0; i < *cutnnz; ++i )
1364 {
1365 SCIP_Real QUAD(val);
1366
1367 assert(cutinds[i] >= 0);
1368 assert(vars[cutinds[i]] != NULL);
1369
1370 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1371
1372 if( QUAD_TO_DBL(val) < 0.0 )
1373 {
1374 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1375
1376 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
1377
1378 SCIPquadprecProdQD(val, val, lb);
1379
1380 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
1381 }
1382 else
1383 {
1384 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1385
1386 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
1387
1388 SCIPquadprecProdQD(val, val, ub);
1389
1390 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
1391 }
1392 }
1393
1394 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
1395 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
1396 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
1397 }
1398 else
1399 {
1400 /* otherwise, apply the equilibrium scaling */
1401 isintegral = FALSE;
1402
1403 /* perform the scaling */
1404 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
1405 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
1406 maxabsintval *= equiscale;
1407
1408 for( i = 0; i < *cutnnz; ++i )
1409 {
1410 SCIP_Real QUAD(val);
1411
1412 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1413 SCIPquadprecProdQD(val, val, equiscale);
1414 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1415 }
1416 }
1417 }
1418 else
1419 {
1420 /* cut has integer and continuous variables, so scale it to equilibrium */
1421 SCIP_Real scale;
1422 SCIP_Real maxabsval;
1423
1424 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
1425 maxabsval = MIN(maxabsval, maxabsintval);
1426 maxabsval = MAX(maxabsval, maxabscontval);
1427
1428 scale = 1.0 / maxabsval; /*lint !e795*/
1429
1430 /* perform the scaling */
1431 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
1432 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
1433 maxabsintval *= scale;
1434
1435 for( i = 0; i < *cutnnz; ++i )
1436 {
1437 SCIP_Real QUAD(val);
1438
1439 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1440 SCIPquadprecProdQD(val, val, scale);
1441 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1442 }
1443 }
1444
1445 maxact = QUAD_TO_DBL(maxacttmp);
1446
1447 /* check again for redundancy after scaling */
1448 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1449 {
1450 *redundant = TRUE;
1451 return SCIP_OKAY;
1452 }
1453
1454 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1455 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
1456 return SCIP_OKAY;
1457
1458 /* 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 */
1459 SCIPsortInt(cutinds, *cutnnz);
1460 SCIPsortDownInd(cutinds, compareAbsCoefsQuad, (void*) cutcoefs, *cutnnz);
1461
1462 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1463 for( i = 0; i < *cutnnz; )
1464 {
1465 SCIP_Real QUAD(val);
1466
1467 if( cutinds[i] >= nintegralvars )
1468 {
1469 ++i;
1470 continue;
1471 }
1472
1473 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1474
1475 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1476
1477 if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
1478 {
1479 SCIP_Real QUAD(coef);
1480 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1481
1482 SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
1483
1484 if( isintegral )
1485 {
1486 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1487 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1488 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1489 }
1490
1491 if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
1492 {
1493 SCIP_Real QUAD(delta);
1494 SCIP_Real QUAD(tmp);
1495
1496 SCIPquadprecSumQQ(delta, -val, coef);
1497 SCIPquadprecProdQD(delta, delta, lb);
1498
1499 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1500 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1501 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
1502 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1503
1504 QUAD_ASSIGN_Q(*cutrhs, tmp);
1505
1506 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
1507
1508 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
1509 {
1510 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1511 maxact = QUAD_TO_DBL(maxacttmp);
1512 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1513 }
1514 else
1515 {
1516 QUAD_ASSIGN(coef, 0.0);
1517 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1518 --(*cutnnz);
1519 cutinds[i] = cutinds[*cutnnz];
1520 continue;
1521 }
1522 }
1523 }
1524 else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
1525 {
1526 SCIP_Real QUAD(coef);
1527 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1528
1529 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
1530
1531 if( isintegral )
1532 {
1533 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1534 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1535 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1536 }
1537
1538 if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
1539 {
1540 SCIP_Real QUAD(delta);
1541 SCIP_Real QUAD(tmp);
1542
1543 SCIPquadprecSumQQ(delta, -val, coef);
1544 SCIPquadprecProdQD(delta, delta, ub);
1545
1546 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1547 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1548 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
1549 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1550
1551 QUAD_ASSIGN_Q(*cutrhs, tmp);
1552
1553 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
1554
1555 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
1556 {
1557 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1558 maxact = QUAD_TO_DBL(maxacttmp);
1559 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1560 }
1561 else
1562 {
1563 QUAD_ASSIGN(coef, 0.0);
1564 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1565 --(*cutnnz);
1566 cutinds[i] = cutinds[*cutnnz];
1567 continue;
1568 }
1569 }
1570 }
1571 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1572 break;
1573
1574 ++i;
1575 }
1576
1577 return SCIP_OKAY;
1578}
1579
1580/** multiplies a parameter for a variable in a row safely (using variable bounds and increasing the rhs)
1581 *
1582 * @return the scaled value
1583 */
1584static
1586 SCIP* scip, /**< SCIP structure */
1587 SCIP_Real val, /**< the value that should be scaled */
1588 SCIP_Real scale, /**< scaling factor */
1589 SCIP_Bool cutislocal, /**< should local or global bounds be used */
1590 SCIP_VAR* var, /**< the variable that is relevant */
1591 SCIP_Real* rhschange, /**< resulting change in rhs of row */
1592 SCIP_Bool* success /**< was the operation successful? (false if no bounds) */
1593 )
1594{
1595 SCIP_ROUNDMODE previousroundmode;
1596 SCIP_INTERVAL valinterval;
1597 SCIP_Real ub;
1598 SCIP_Real lb;
1599 SCIP_Real newval = 0.0;
1600
1601 assert(SCIPisExact(scip));
1602
1603 previousroundmode = SCIPintervalGetRoundingMode();
1605
1606 *rhschange = 0;
1607
1608 SCIPintervalSet(&valinterval, val);
1609 SCIPintervalMulScalar(SCIPinfinity(scip), &valinterval, valinterval, scale);
1610
1611 lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
1612 ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
1613
1614 *success = TRUE;
1615
1616 if( lb > -SCIPinfinity(scip) && lb >= 0 )
1617 {
1618 SCIPdebugMessage("Lb positive, no change in rhs needed \n");
1619 newval = SCIPintervalGetInf(valinterval);
1620 }
1621 else if(ub < SCIPinfinity(scip) && ub <= 0 )
1622 {
1623 SCIPdebugMessage("Ub negative, no change in rhs needed \n");
1624 newval = SCIPintervalGetSup(valinterval);
1625 }
1626 else if( lb > -SCIPinfinity(scip) )
1627 {
1628 newval = SCIPintervalGetInf(valinterval);
1630 *rhschange = (SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval)) * (-lb);
1631 SCIPdebugMessage("Using lb %.17g corrected by %.17g. Change to rhs: %.17g \n", SCIPvarGetLbGlobal(var), -SCIPintervalGetSup(valinterval) + SCIPintervalGetInf(valinterval), *rhschange);
1632 }
1633 else if( ub < SCIPinfinity(scip) )
1634 {
1635 newval = SCIPintervalGetSup(valinterval);
1637 *rhschange = (SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval)) * (ub);
1638 SCIPdebugMessage("Using ub %.17g corrected by %.17g. Change to rhs: %.17g \n", SCIPvarGetUbGlobal(var), SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval), *rhschange);
1639 }
1640 else
1641 {
1642 *success = FALSE;
1643 SCIPintervalSetRoundingMode(previousroundmode);
1644 return newval;
1645 }
1646
1647 SCIPintervalSetRoundingMode(previousroundmode);
1648
1649 return newval;
1650}
1651
1652/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
1653 * see cons_linear.c consdataTightenCoefs() for details;
1654 *
1655 * This is the safe version of cutTightenCoefs() below.
1656 */
1657static
1659 SCIP* scip, /**< SCIP data structure */
1660 SCIP_Bool cutislocal, /**< is the cut local? */
1661 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1662 SCIP_Real* cutrhs, /**< the right hand side of the cut */
1663 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1664 int* cutnnz, /**< the number of non-zeros in the cut */
1665 SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
1666 )
1667{ /*lint --e{644}*/
1668 int i;
1669 int nintegralvars;
1670 SCIP_Bool isintegral = TRUE;
1671 SCIP_VAR** vars;
1672 SCIP_INTERVAL maxact;
1673 SCIP_INTERVAL tmp;
1674 SCIP_Real maxabsintval = 0.0;
1675 SCIP_Real maxabscontval = 0.0;
1676 SCIP_ROUNDMODE previousroundmode;
1677 SCIP_MIRINFO* mirinfo = NULL;
1678
1679 assert(SCIPisExact(scip));
1680
1681 if( SCIPisCertified(scip) )
1682 {
1684 assert(mirinfo != NULL);
1685 }
1686
1687 SCIPintervalSet(&maxact, 0.0);
1688
1689 vars = SCIPgetVars(scip);
1690 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1691
1692 assert(redundant != NULL);
1693 *redundant = FALSE;
1694
1695 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
1696 for( i = 0; i < *cutnnz; ++i )
1697 {
1698 SCIP_Real val;
1699
1700 assert(cutinds[i] >= 0);
1701 assert(vars[cutinds[i]] != NULL);
1702
1703 val = cutcoefs[cutinds[i]];
1704
1705 if( val < 0.0 )
1706 {
1707 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1708
1709 if( SCIPisInfinity(scip, -lb) )
1710 return SCIP_OKAY;
1711
1712 if( cutinds[i] < nintegralvars )
1713 maxabsintval = MAX(maxabsintval, -val);
1714 else
1715 {
1716 maxabscontval = MAX(maxabscontval, -val);
1717 isintegral = FALSE;
1718 }
1719
1720 SCIPintervalSet(&tmp, val);
1721 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, lb);
1722 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
1723 }
1724 else
1725 {
1726 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1727
1728 if( SCIPisInfinity(scip, ub) )
1729 return SCIP_OKAY;
1730
1731 if( cutinds[i] < nintegralvars )
1732 maxabsintval = MAX(maxabsintval, val);
1733 else
1734 {
1735 maxabscontval = MAX(maxabscontval, val);
1736 isintegral = FALSE;
1737 }
1738
1739 SCIPintervalSet(&tmp, val);
1740 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, ub);
1741 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
1742 }
1743 }
1744
1745 /* cut is redundant in activity bounds */
1746 if( SCIPintervalGetSup(maxact) <= *cutrhs )
1747 {
1748 *redundant = TRUE;
1749 return SCIP_OKAY;
1750 }
1751
1752 previousroundmode = SCIPintervalGetRoundingMode();
1753
1754 /* cut is only on integral variables, try to scale to integral coefficients */
1755 if( isintegral )
1756 {
1757 SCIP_Real equiscale;
1758 SCIP_Real intscalar;
1759 SCIP_Bool success;
1760 SCIP_Real* intcoeffs;
1761 SCIP_Real rhschange;
1762
1763 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
1764
1765 equiscale = 1.0 / MAX(maxabscontval, maxabsintval);
1766
1767 for( i = 0; i < *cutnnz; ++i )
1768 {
1769 SCIP_Real val;
1770
1771 val = cutcoefs[cutinds[i]];
1772 val *= equiscale;
1773
1774 intcoeffs[i] = val;
1775 }
1776
1778 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
1779
1780 SCIPfreeBufferArray(scip, &intcoeffs);
1781
1782 if( success )
1783 {
1784 /* if successful, apply the scaling */
1786 intscalar *= equiscale;
1787
1788 *cutrhs *= intscalar;
1789
1790 if( SCIPisCertified(scip) )
1791 {
1792 assert(mirinfo != NULL);
1793 mirinfo->scale = intscalar;
1794 }
1795
1796 for( i = 0; i < *cutnnz; )
1797 {
1798 SCIP_Real val;
1799 SCIP_Real intval;
1800
1801 val = cutcoefs[cutinds[i]];
1802 val = scaleValSafely(scip, val, intscalar, cutislocal, vars[cutinds[i]], &rhschange, &success);
1803
1804 *cutrhs += rhschange;
1805
1806 if( !success )
1807 {
1808 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
1809 *redundant = TRUE;
1810 SCIPintervalSetRoundingMode(previousroundmode);
1811 return SCIP_OKAY;
1812 }
1813 intval = SCIPround(scip, val);
1814
1815 if( chgCoeffWithBoundSafely(scip, vars[cutinds[i]], val, intval, cutislocal, cutrhs) )
1816 {
1817 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
1818 SCIPintervalSetRoundingMode(previousroundmode);
1819 *redundant = TRUE;
1820 return SCIP_OKAY;
1821 }
1822
1823 if( intval != 0.0 )
1824 {
1825 val = intval;
1826 cutcoefs[cutinds[i]] = val;
1827 ++i;
1828 }
1829 else
1830 {
1831 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
1832 val = 0.0;
1833 cutcoefs[cutinds[i]] = val;
1834 --(*cutnnz);
1835 cutinds[i] = cutinds[*cutnnz];
1836 }
1837 }
1838
1839 if( SCIPisCertified(scip) )
1840 {
1841 assert(mirinfo != NULL);
1842 mirinfo->unroundedrhs = *cutrhs;
1843 }
1844 *cutrhs = floor(*cutrhs); /*lint !e835*/
1845
1846 /* recompute the maximal activity after scaling to integral values */
1847 SCIPintervalSet(&maxact, 0.0);
1848 maxabsintval = 0.0;
1849
1850 for( i = 0; i < *cutnnz; ++i )
1851 {
1852 SCIP_Real val;
1853
1854 assert(cutinds[i] >= 0);
1855 assert(vars[cutinds[i]] != NULL);
1856
1857 val = cutcoefs[cutinds[i]];
1858
1859 if( val < 0.0 )
1860 {
1861 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1862
1863 maxabsintval = MAX(maxabsintval, -val);
1864
1865 SCIPintervalSet(&tmp, val);
1866 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, lb);
1867 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
1868 }
1869 else
1870 {
1871 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1872
1873 maxabsintval = MAX(maxabsintval, val);
1874
1875 SCIPintervalSet(&tmp, val);
1876 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, ub);
1877 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
1878 }
1879 }
1880
1881 assert(EPSISINT(SCIPintervalGetSup(maxact), 1e-4));/*lint !e666*/
1882 /* check again for redundancy */
1883 if( SCIPisFeasLE(scip, SCIPintervalGetSup(maxact), *cutrhs) )
1884 {
1885 *redundant = TRUE;
1886 SCIPintervalSetRoundingMode(previousroundmode);
1887 return SCIP_OKAY;
1888 }
1889 }
1890 else
1891 {
1892 /* otherwise, apply the equilibrium scaling */
1893
1894 /* perform the scaling */
1895 SCIPintervalMulScalar(SCIPinfinity(scip), &maxact, maxact, equiscale);
1897
1898 *cutrhs *= equiscale;
1899 maxabsintval *= equiscale;
1900 if( SCIPisCertified(scip) )
1901 {
1902 assert(mirinfo != NULL);
1903 mirinfo->scale = equiscale;
1904 }
1905
1906 for( i = 0; i < *cutnnz; ++i )
1907 {
1908 SCIP_Real val;
1909
1910 val = cutcoefs[cutinds[i]];
1911 val = scaleValSafely(scip, val, equiscale, cutislocal, vars[cutinds[i]], &rhschange, &success);
1912
1913 if( !success )
1914 {
1915 *redundant = TRUE;
1916 SCIPintervalSetRoundingMode(previousroundmode);
1917 return SCIP_OKAY;
1918 }
1919 cutcoefs[cutinds[i]] = val;
1920 *cutrhs += rhschange;
1921 }
1922 }
1923 }
1924 else
1925 {
1926 /* cut has integer and continuous variables, so scale it to equilibrium */
1927 SCIP_Real scale;
1928 SCIP_Real maxabsval;
1929 SCIP_Bool success;
1930 SCIP_Real rhschange;
1931
1932 maxabsval = SCIPintervalGetSup(maxact) - *cutrhs;
1933 maxabsval = MIN(maxabsval, maxabsintval);
1934 maxabsval = MAX(maxabsval, maxabscontval);
1935
1936 scale = 1.0 / maxabsval; /*lint !e795*/
1937
1938 /* perform the scaling */
1939 SCIPintervalSet(&maxact, scale);
1941 *cutrhs *= scale;
1942 maxabsintval *= scale;
1943 if( SCIPisCertified(scip) )
1944 {
1945 assert(mirinfo != NULL);
1946 mirinfo->scale = scale;
1947 }
1948
1949 for( i = 0; i < *cutnnz; ++i )
1950 {
1951 SCIP_Real val;
1952
1953 val = cutcoefs[cutinds[i]];
1954 val = scaleValSafely(scip, val, scale, cutislocal, vars[cutinds[i]], &rhschange, &success);
1955
1956 *cutrhs += rhschange;
1957
1958 if( !success )
1959 {
1960 *redundant = TRUE;
1961 SCIPintervalSetRoundingMode(previousroundmode);
1962 return SCIP_OKAY;
1963 }
1964 cutcoefs[cutinds[i]] = val;
1965 }
1966 }
1967
1968 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1969 if( SCIPisGT(scip, SCIPintervalGetSup(maxact) - maxabsintval, *cutrhs) )
1970 {
1971 SCIPintervalSetRoundingMode(previousroundmode);
1972 return SCIP_OKAY;
1973 }
1974
1975 SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
1976
1977#ifdef SCIP_DISABLED_CODE
1978 /** @todo implement and certify coefficient tightening for cuts in exact solving mode */
1979 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1980 for( i = 0; i < *cutnnz && FALSE; )
1981 {
1982 SCIP_Real QUAD(val);
1983
1984 if( cutinds[i] >= nintegralvars )
1985 {
1986 ++i;
1987 continue;
1988 }
1989
1990 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1991
1992 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1993
1994 if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
1995 {
1996 SCIP_Real QUAD(coef);
1997 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1998
1999 SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
2000
2001 if( isintegral )
2002 {
2003 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
2004 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
2005 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
2006 }
2007
2008 if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
2009 {
2010 SCIP_Real QUAD(delta);
2011 SCIP_Real QUAD(tmp);
2012
2013 SCIPquadprecSumQQ(delta, -val, coef);
2014 SCIPquadprecProdQD(delta, delta, lb);
2015
2016 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
2017 SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2018 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
2019 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
2020
2021 QUAD_ASSIGN_Q(*cutrhs, tmp);
2022
2023 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
2024
2025 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
2026 {
2027 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2028 maxact = QUAD_TO_DBL(maxacttmp);
2029 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
2030 }
2031 else
2032 {
2033 QUAD_ASSIGN(coef, 0.0);
2034 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
2035 --(*cutnnz);
2036 cutinds[i] = cutinds[*cutnnz];
2037 continue;
2038 }
2039 }
2040 }
2041 else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
2042 {
2043 SCIP_Real QUAD(coef);
2044 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2045
2046 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
2047
2048 if( isintegral )
2049 {
2050 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
2051 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
2052 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
2053 }
2054
2055 if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
2056 {
2057 SCIP_Real QUAD(delta);
2058 SCIP_Real QUAD(tmp);
2059
2060 SCIPquadprecSumQQ(delta, -val, coef);
2061 SCIPquadprecProdQD(delta, delta, ub);
2062
2063 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
2064 SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2065 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
2066 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
2067
2068 QUAD_ASSIGN_Q(*cutrhs, tmp);
2069
2070 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
2071
2072 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
2073 {
2074 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2075 maxact = QUAD_TO_DBL(maxacttmp);
2076 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
2077 }
2078 else
2079 {
2080 QUAD_ASSIGN(coef, 0.0);
2081 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
2082 --(*cutnnz);
2083 cutinds[i] = cutinds[*cutnnz];
2084 continue;
2085 }
2086 }
2087 }
2088 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
2089 break;
2090
2091 ++i;
2092 }
2093#endif /*lint --e{438}*/
2094
2095 return SCIP_OKAY;
2096}
2097
2098
2099/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
2100 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse array;
2101 */
2102static
2104 SCIP* scip, /**< SCIP data structure */
2105 SCIP_Bool cutislocal, /**< is the cut local? */
2106 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
2107 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
2108 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
2109 int* cutnnz, /**< the number of non-zeros in the cut */
2110 SCIP_Bool* redundant /**< pointer to return whtether the cut was detected to be redundant */
2111 )
2112{
2113 int i;
2114 int nintegralvars;
2115 SCIP_Bool isintegral = TRUE;
2116 SCIP_VAR** vars;
2117 SCIP_Real QUAD(maxacttmp);
2118 SCIP_Real maxact;
2119 SCIP_Real maxabsintval = 0.0;
2120 SCIP_Real maxabscontval = 0.0;
2121
2122 assert(!SCIPisExact(scip));
2123
2124 QUAD_ASSIGN(maxacttmp, 0.0);
2125
2126 vars = SCIPgetVars(scip);
2127 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
2128
2129 assert(redundant != NULL);
2130 *redundant = FALSE;
2131
2132 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
2133 for( i = 0; i < *cutnnz; ++i )
2134 {
2135 SCIP_Real val;
2136 SCIP_Real QUAD(quadprod);
2137
2138 assert(cutinds[i] >= 0);
2139 assert(vars[cutinds[i]] != NULL);
2140
2141 val = cutcoefs[cutinds[i]];
2142
2143 if( val < 0.0 )
2144 {
2145 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2146
2147 if( SCIPisInfinity(scip, -lb) )
2148 return SCIP_OKAY;
2149
2150 if( cutinds[i] < nintegralvars )
2151 maxabsintval = MAX(maxabsintval, -val);
2152 else
2153 {
2154 maxabscontval = MAX(maxabscontval, -val);
2155 isintegral = FALSE;
2156 }
2157
2158 SCIPquadprecProdDD(quadprod, val, lb);
2159 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2160 }
2161 else
2162 {
2163 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2164
2165 if( SCIPisInfinity(scip, ub) )
2166 return SCIP_OKAY;
2167
2168 if( cutinds[i] < nintegralvars )
2169 maxabsintval = MAX(maxabsintval, val);
2170 else
2171 {
2172 maxabscontval = MAX(maxabscontval, val);
2173 isintegral = FALSE;
2174 }
2175
2176 SCIPquadprecProdDD(quadprod, val, ub);
2177 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2178 }
2179 }
2180
2181 maxact = QUAD_TO_DBL(maxacttmp);
2182
2183 /* cut is redundant in activity bounds */
2184 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
2185 {
2186 *redundant = TRUE;
2187 return SCIP_OKAY;
2188 }
2189
2190 /* cut is only on integral variables, try to scale to integral coefficients */
2191 if( isintegral )
2192 {
2193 SCIP_Real equiscale;
2194 SCIP_Real intscalar;
2195 SCIP_Bool success;
2196 SCIP_Real* intcoeffs;
2197
2198 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
2199
2200 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
2201
2202 for( i = 0; i < *cutnnz; ++i )
2203 {
2204 SCIP_Real val;
2205
2206 val = equiscale * cutcoefs[cutinds[i]];
2207
2208 intcoeffs[i] = val;
2209 }
2210
2212 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
2213
2214 SCIPfreeBufferArray(scip, &intcoeffs);
2215
2216 if( success )
2217 {
2218 /* if successful, apply the scaling */
2219 intscalar *= equiscale;
2220 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
2221
2222 for( i = 0; i < *cutnnz; )
2223 {
2224 SCIP_Real val;
2225 SCIP_Real intval;
2226
2227 val = cutcoefs[cutinds[i]];
2228 val *= intscalar;
2229
2230 intval = SCIPround(scip, val);
2231
2232 if( chgCoeffWithBound(scip, vars[cutinds[i]], val, intval, cutislocal, QUAD(cutrhs)) )
2233 {
2234 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
2235 *redundant = TRUE;
2236 return SCIP_OKAY;
2237 }
2238
2239 if( intval != 0.0 )
2240 {
2241 cutcoefs[cutinds[i]] = intval;
2242 ++i;
2243 }
2244 else
2245 {
2246 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
2247 cutcoefs[cutinds[i]] = 0.0;
2248 --(*cutnnz);
2249 cutinds[i] = cutinds[*cutnnz];
2250 }
2251 }
2252
2253 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
2254
2255 /* recompute the maximal activity after scaling to integral values */
2256 QUAD_ASSIGN(maxacttmp, 0.0);
2257 maxabsintval = 0.0;
2258
2259 for( i = 0; i < *cutnnz; ++i )
2260 {
2261 SCIP_Real val;
2262 SCIP_Real QUAD(quadprod);
2263
2264 assert(cutinds[i] >= 0);
2265 assert(vars[cutinds[i]] != NULL);
2266
2267 val = cutcoefs[cutinds[i]];
2268
2269 if( val < 0.0 )
2270 {
2271 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2272
2273 maxabsintval = MAX(maxabsintval, -val);
2274
2275 SCIPquadprecProdDD(quadprod, val, lb);
2276 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2277 }
2278 else
2279 {
2280 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2281
2282 maxabsintval = MAX(maxabsintval, val);
2283
2284 SCIPquadprecProdDD(quadprod, val, ub);
2285 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2286 }
2287 }
2288
2289 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
2290 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
2291 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
2292 }
2293 else
2294 {
2295 /* otherwise, apply the equilibrium scaling */
2296 isintegral = FALSE;
2297
2298 /* perform the scaling */
2299 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
2300 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
2301 maxabsintval *= equiscale;
2302
2303 for( i = 0; i < *cutnnz; ++i )
2304 cutcoefs[cutinds[i]] *= equiscale;
2305 }
2306 }
2307 else
2308 {
2309 /* cut has integer and continuous variables, so scale it to equilibrium */
2310 SCIP_Real scale;
2311 SCIP_Real maxabsval;
2312
2313 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
2314 maxabsval = MIN(maxabsval, maxabsintval);
2315 maxabsval = MAX(maxabsval, maxabscontval);
2316
2317 scale = 1.0 / maxabsval; /*lint !e795*/
2318
2319 /* perform the scaling */
2320 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
2321 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
2322 maxabsintval *= scale;
2323
2324 for( i = 0; i < *cutnnz; ++i )
2325 cutcoefs[cutinds[i]] *= scale;
2326 }
2327
2328 maxact = QUAD_TO_DBL(maxacttmp);
2329
2330 /* check again for redundancy after scaling */
2331 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
2332 {
2333 *redundant = TRUE;
2334 return SCIP_OKAY;
2335 }
2336
2337 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
2338 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
2339 return SCIP_OKAY;
2340
2341 /* 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 */
2342 SCIPsortInt(cutinds, *cutnnz);
2343 SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
2344
2345 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
2346 for( i = 0; i < *cutnnz; )
2347 {
2348 SCIP_Real val;
2349
2350 if( cutinds[i] >= nintegralvars )
2351 {
2352 ++i;
2353 continue;
2354 }
2355
2356 val = cutcoefs[cutinds[i]];
2357
2358 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
2359
2360 if( val < 0.0 && SCIPisLE(scip, maxact + val, QUAD_TO_DBL(*cutrhs)) )
2361 {
2362 SCIP_Real QUAD(coef);
2363 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2364
2365 SCIPquadprecSumQQ(coef, -maxacttmp, *cutrhs);
2366
2367 if( isintegral )
2368 {
2369 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
2370 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
2371 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
2372 }
2373
2374 if( QUAD_TO_DBL(coef) > val )
2375 {
2376 SCIP_Real QUAD(delta);
2377 SCIP_Real QUAD(tmp);
2378
2379 SCIPquadprecSumQD(delta, coef, -val);
2380 SCIPquadprecProdQD(delta, delta, lb);
2381
2382 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
2383 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2384 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
2385 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
2386
2387 QUAD_ASSIGN_Q(*cutrhs, tmp);
2388
2389 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
2390
2391 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
2392 {
2393 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2394 maxact = QUAD_TO_DBL(maxacttmp);
2395 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
2396 }
2397 else
2398 {
2399 cutcoefs[cutinds[i]] = 0.0;
2400 --(*cutnnz);
2401 cutinds[i] = cutinds[*cutnnz];
2402 continue;
2403 }
2404 }
2405 }
2406 else if( val > 0.0 && SCIPisLE(scip, maxact - val, QUAD_TO_DBL(*cutrhs)) )
2407 {
2408 SCIP_Real QUAD(coef);
2409 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2410
2411 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
2412
2413 if( isintegral )
2414 {
2415 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
2416 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
2417 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
2418 }
2419
2420 if( QUAD_TO_DBL(coef) < val )
2421 {
2422 SCIP_Real QUAD(delta);
2423 SCIP_Real QUAD(tmp);
2424
2425 SCIPquadprecSumQD(delta, coef, -val);
2426 SCIPquadprecProdQD(delta, delta, ub);
2427
2428 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
2429 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2430 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
2431 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
2432
2433 QUAD_ASSIGN_Q(*cutrhs, tmp);
2434
2435 assert(! SCIPisNegative(scip, QUAD_TO_DBL(coef)));
2436
2437 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
2438 {
2439 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2440 maxact = QUAD_TO_DBL(maxacttmp);
2441 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
2442 }
2443 else
2444 {
2445 cutcoefs[cutinds[i]] = 0.0;
2446 --(*cutnnz);
2447 cutinds[i] = cutinds[*cutnnz];
2448 continue;
2449 }
2450 }
2451 }
2452 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
2453 break;
2454
2455 ++i;
2456 }
2457
2458 return SCIP_OKAY;
2459}
2460
2461/** perform activity based coefficient tightening on the given cut; returns TRUE if the cut was detected
2462 * to be redundant due to activity bounds
2463 *
2464 * See also cons_linear.c:consdataTightenCoefs().
2465 */
2467 SCIP* scip, /**< SCIP data structure */
2468 SCIP_Bool cutislocal, /**< is the cut local? */
2469 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
2470 SCIP_Real* cutrhs, /**< the right hand side of the cut */
2471 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
2472 int* cutnnz, /**< the number of non-zeros in the cut */
2473 int* nchgcoefs /**< number of changed coefficients */
2474 )
2475{
2476 int i;
2477 int nintegralvars;
2478 SCIP_VAR** vars;
2479 SCIP_Real* absvals;
2480 SCIP_Real QUAD(maxacttmp);
2481 SCIP_Real maxact;
2482 SCIP_Real maxabsval = 0.0;
2483 SCIP_Bool redundant = FALSE;
2484
2485 assert(nchgcoefs != NULL);
2486
2487 QUAD_ASSIGN(maxacttmp, 0.0);
2488
2489 vars = SCIPgetVars(scip);
2490 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
2491 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &absvals, *cutnnz) );
2492
2493 assert(nchgcoefs != NULL);
2494 *nchgcoefs = 0;
2495
2496 for( i = 0; i < *cutnnz; ++i )
2497 {
2498 SCIP_Real QUAD(quadprod);
2499
2500 assert(cutinds[i] >= 0);
2501 assert(vars[cutinds[i]] != NULL);
2502
2503 if( cutcoefs[i] < 0.0 )
2504 {
2505 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2506
2507 if( SCIPisInfinity(scip, -lb) )
2508 goto TERMINATE;
2509
2510 if( cutinds[i] < nintegralvars )
2511 {
2512 maxabsval = MAX(maxabsval, -cutcoefs[i]);
2513 absvals[i] = -cutcoefs[i];
2514 }
2515 else
2516 absvals[i] = 0.0;
2517
2518 SCIPquadprecProdDD(quadprod, lb, cutcoefs[i]);
2519 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2520 }
2521 else
2522 {
2523 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2524
2525 if( SCIPisInfinity(scip, ub) )
2526 goto TERMINATE;
2527
2528 if( cutinds[i] < nintegralvars )
2529 {
2530 maxabsval = MAX(maxabsval, cutcoefs[i]);
2531 absvals[i] = cutcoefs[i];
2532 }
2533 else
2534 absvals[i] = 0.0;
2535
2536 SCIPquadprecProdDD(quadprod, ub, cutcoefs[i]);
2537 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
2538 }
2539 }
2540
2541 maxact = QUAD_TO_DBL(maxacttmp);
2542
2543 /* cut is redundant in activity bounds */
2544 if( SCIPisFeasLE(scip, maxact, *cutrhs) )
2545 {
2546 redundant = TRUE;
2547 goto TERMINATE;
2548 }
2549
2550 /* terminate, because coefficient tightening cannot be performed; also excludes the case in which no integral variable is present */
2551 if( SCIPisGT(scip, maxact - maxabsval, *cutrhs) )
2552 goto TERMINATE;
2553
2554 SCIPsortDownRealRealInt(absvals, cutcoefs, cutinds, *cutnnz);
2555 SCIPfreeBufferArray(scip, &absvals);
2556
2557 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
2558 for( i = 0; i < *cutnnz; ++i )
2559 {
2560 /* due to sorting, we can exit if we reached a continuous variable: all further integral variables have 0 coefficents anyway */
2561 if( cutinds[i] >= nintegralvars )
2562 break;
2563
2564 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
2565
2566 if( cutcoefs[i] < 0.0 && SCIPisLE(scip, maxact + cutcoefs[i], *cutrhs) )
2567 {
2568 SCIP_Real coef = (*cutrhs) - maxact;
2569 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
2570
2571 coef = SCIPfloor(scip, coef);
2572
2573 if( coef > cutcoefs[i] )
2574 {
2575 SCIP_Real QUAD(delta);
2576 SCIP_Real QUAD(tmp);
2577
2578 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
2579 SCIPquadprecProdQD(delta, delta, lb);
2580
2581 SCIPquadprecSumQD(tmp, delta, *cutrhs);
2582 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2583 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp), lb,
2584 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
2585
2586 *cutrhs = QUAD_TO_DBL(tmp);
2587
2588 assert(!SCIPisPositive(scip, coef));
2589
2590 ++(*nchgcoefs);
2591
2592 if( SCIPisNegative(scip, coef) )
2593 {
2594 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2595 maxact = QUAD_TO_DBL(maxacttmp);
2596 cutcoefs[i] = coef;
2597 }
2598 else
2599 {
2600 --(*cutnnz);
2601 cutinds[i] = cutinds[*cutnnz];
2602 cutcoefs[i] = cutcoefs[*cutnnz];
2603 continue;
2604 }
2605 }
2606 }
2607 else if( cutcoefs[i] > 0.0 && SCIPisLE(scip, maxact - cutcoefs[i], *cutrhs) )
2608 {
2609 SCIP_Real coef = maxact - (*cutrhs);
2610 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
2611
2612 coef = SCIPceil(scip, coef);
2613
2614 if( coef < cutcoefs[i] )
2615 {
2616 SCIP_Real QUAD(delta);
2617 SCIP_Real QUAD(tmp);
2618
2619 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
2620 SCIPquadprecProdQD(delta, delta, ub);
2621
2622 SCIPquadprecSumQD(tmp, delta, *cutrhs);
2623 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
2624 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp),
2625 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
2626
2627 *cutrhs = QUAD_TO_DBL(tmp);
2628
2629 assert(!SCIPisNegative(scip, coef));
2630
2631 ++(*nchgcoefs);
2632
2633 if( SCIPisPositive(scip, coef) )
2634 {
2635 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
2636 maxact = QUAD_TO_DBL(maxacttmp);
2637 cutcoefs[i] = coef;
2638 }
2639 else
2640 {
2641 --(*cutnnz);
2642 cutinds[i] = cutinds[*cutnnz];
2643 cutcoefs[i] = cutcoefs[*cutnnz];
2644 continue;
2645 }
2646 }
2647 }
2648 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
2649 break;
2650 }
2651
2652 TERMINATE:
2653 SCIPfreeBufferArrayNull(scip, &absvals);
2654
2655 return redundant;
2656}
2657
2658/* =========================================== aggregation row =========================================== */
2659
2660
2661/** create an empty aggregation row
2662 *
2663 * @note By default, this data structure uses quad precision via double-double arithmetic, i.e., it allocates a
2664 * SCIP_Real array of length two times SCIPgetNVars() for storing the coefficients. In exact solving mode, we
2665 * cannot use quad precision because we need to control the ronding mode, hence only the first SCIPgetNVars()
2666 * entries are used.
2667 */
2669 SCIP* scip, /**< SCIP data structure */
2670 SCIP_AGGRROW** aggrrow /**< pointer to return aggregation row */
2671 )
2672{
2673 int nvars;
2674 assert(scip != NULL);
2675 assert(aggrrow != NULL);
2676
2677 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
2678
2679 nvars = SCIPgetNVars(scip);
2680
2681 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)) );
2682 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->inds, nvars) );
2683
2684 BMSclearMemoryArray((*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars));
2685
2686 (*aggrrow)->local = FALSE;
2687 (*aggrrow)->nnz = 0;
2688 (*aggrrow)->rank = 0;
2689 QUAD_ASSIGN((*aggrrow)->rhs, 0.0);
2690 (*aggrrow)->rowsinds = NULL;
2691 (*aggrrow)->slacksign = NULL;
2692 (*aggrrow)->rowweights = NULL;
2693 (*aggrrow)->nrows = 0;
2694 (*aggrrow)->rowssize = 0;
2695
2696 return SCIP_OKAY;
2697}
2698
2699/** free a aggregation row */
2701 SCIP* scip, /**< SCIP data structure */
2702 SCIP_AGGRROW** aggrrow /**< pointer to aggregation row that should be freed */
2703 )
2704{
2705 int nvars;
2706
2707 assert(scip != NULL);
2708 assert(aggrrow != NULL);
2709
2710 nvars = SCIPgetNVars(scip);
2711
2712 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->inds, nvars);
2713 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)); /*lint !e647*/
2714 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowsinds, (*aggrrow)->rowssize);
2715 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->slacksign, (*aggrrow)->rowssize);
2716 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowweights, (*aggrrow)->rowssize);
2717 SCIPfreeBlockMemory(scip, aggrrow);
2718}
2719
2720/** output aggregation row to file stream */
2722 SCIP* scip, /**< SCIP data structure */
2723 SCIP_AGGRROW* aggrrow, /**< pointer to return aggregation row */
2724 FILE* file /**< output file (or NULL for standard output) */
2725 )
2726{
2727 SCIP_VAR** vars;
2728 SCIP_MESSAGEHDLR* messagehdlr;
2729 int i;
2730
2731 assert(scip != NULL);
2732 assert(aggrrow != NULL);
2733
2734 vars = SCIPgetVars(scip);
2735 assert(vars != NULL);
2736
2737 messagehdlr = SCIPgetMessagehdlr(scip);
2738 assert(messagehdlr);
2739
2740 /* print coefficients */
2741 if( aggrrow->nnz == 0 )
2742 SCIPmessageFPrintInfo(messagehdlr, file, "0 ");
2743
2744 for( i = 0; i < aggrrow->nnz; ++i )
2745 {
2746 SCIP_Real QUAD(val);
2747
2748 QUAD_ARRAY_LOAD(val, aggrrow->vals, aggrrow->inds[i]);
2749 assert(SCIPvarGetProbindex(vars[aggrrow->inds[i]]) == aggrrow->inds[i]);
2750 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", QUAD_TO_DBL(val), SCIPvarGetName(vars[aggrrow->inds[i]]));
2751 }
2752
2753 /* print right hand side */
2754 SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", QUAD_TO_DBL(aggrrow->rhs));
2755}
2756
2757/** copy a aggregation row */
2759 SCIP* scip, /**< SCIP data structure */
2760 SCIP_AGGRROW** aggrrow, /**< pointer to return aggregation row */
2761 SCIP_AGGRROW* source /**< source aggregation row */
2762 )
2763{
2764 int nvars;
2765
2766 assert(scip != NULL);
2767 assert(aggrrow != NULL);
2768 assert(source != NULL);
2769
2770 nvars = SCIPgetNVars(scip);
2771 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
2772
2773 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->vals, source->vals, QUAD_ARRAY_SIZE(nvars)) );
2774 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->inds, source->inds, nvars) );
2775 (*aggrrow)->nnz = source->nnz;
2776 QUAD_ASSIGN_Q((*aggrrow)->rhs, source->rhs);
2777
2778 if( source->nrows > 0 )
2779 {
2780 assert(source->rowsinds != NULL);
2781 assert(source->slacksign != NULL);
2782 assert(source->rowweights != NULL);
2783
2784 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowsinds, source->rowsinds, source->nrows) );
2785 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->slacksign, source->slacksign, source->nrows) );
2786 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowweights, source->rowweights, source->nrows) );
2787 }
2788 else
2789 {
2790 (*aggrrow)->rowsinds = NULL;
2791 (*aggrrow)->slacksign = NULL;
2792 (*aggrrow)->rowweights = NULL;
2793 }
2794
2795 (*aggrrow)->nrows = source->nrows;
2796 (*aggrrow)->rowssize = source->nrows;
2797 (*aggrrow)->rank = source->rank;
2798 (*aggrrow)->local = source->local;
2799
2800 return SCIP_OKAY;
2801}
2802
2803/** add weighted row to aggregation row */
2805 SCIP* scip, /**< SCIP data structure */
2806 SCIP_AGGRROW* aggrrow, /**< aggregation row */
2807 SCIP_ROW* row, /**< row to add to aggregation row */
2808 SCIP_Real weight, /**< scale for adding given row to aggregation row */
2809 int sidetype /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
2810 )
2811{
2812 SCIP_Real QUAD(quadprod);
2813 SCIP_Real sideval;
2814 SCIP_Bool uselhs;
2815 int i;
2816
2817 assert(row->lppos >= 0);
2818
2819 /* update local flag */
2820 aggrrow->local = aggrrow->local || row->local;
2821
2822 /* update rank */
2823 aggrrow->rank = MAX(row->rank, aggrrow->rank);
2824
2825 i = aggrrow->nrows++;
2826
2827 if( aggrrow->nrows > aggrrow->rowssize )
2828 {
2829 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
2830 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
2831 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
2832 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
2833 aggrrow->rowssize = newsize;
2834 }
2835 aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
2836 aggrrow->rowweights[i] = weight;
2837
2838 if( sidetype == -1 )
2839 {
2840 assert( ! SCIPisInfinity(scip, -row->lhs) );
2841 uselhs = TRUE;
2842 }
2843 else if( sidetype == 1 )
2844 {
2845 assert( ! SCIPisInfinity(scip, row->rhs) );
2846 uselhs = FALSE;
2847 }
2848 else
2849 {
2850 /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
2851 * If possible, use the side that leads to a positive slack value in the summation.
2852 */
2853 if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
2854 uselhs = TRUE;
2855 else
2856 uselhs = FALSE;
2857 }
2858
2859 if( uselhs )
2860 {
2861 aggrrow->slacksign[i] = -1;
2862 sideval = row->lhs - row->constant;
2863 if( row->integral )
2864 sideval = SCIPceil(scip, sideval); /* row is integral: round left hand side up */
2865 }
2866 else
2867 {
2868 aggrrow->slacksign[i] = +1;
2869 sideval = row->rhs - row->constant;
2870 if( row->integral )
2871 sideval = SCIPfloor(scip, sideval); /* row is integral: round right hand side up */
2872 }
2873
2874 SCIPquadprecProdDD(quadprod, weight, sideval);
2875 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
2876
2877 /* add up coefficients */
2878 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
2879
2880 return SCIP_OKAY;
2881}
2882
2883/** add weighted row to aggregation row
2884 *
2885 * @note this method is the variant of SCIPaggrRowAddRow that is safe to use in exact solving mode
2886 */
2888 SCIP* scip, /**< SCIP data structure */
2889 SCIP_AGGRROW* aggrrow, /**< aggregation row */
2890 SCIP_ROW* row, /**< row to add to aggregation row */
2891 SCIP_Real weight, /**< scale for adding given row to aggregation row */
2892 int sidetype, /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
2893 SCIP_Bool* success /**< was the row added successfully */
2894 )
2895{
2896 SCIP_Real sideval;
2897 SCIP_Real sidevalchg;
2898 SCIP_Bool uselhs;
2899 SCIP_ROW* userow;
2900 SCIP_ROWEXACT* rowexact;
2901 SCIP_ROUNDMODE previousroundmode;
2902 int i;
2903
2904 assert(SCIPisExact(scip));
2905 assert(success != NULL);
2906
2907 /* update local flag */
2908 aggrrow->local = aggrrow->local || row->local;
2909
2910 /* update rank */
2911 aggrrow->rank = MAX(row->rank, aggrrow->rank);
2912
2913 i = aggrrow->nrows++;
2914
2915 if( aggrrow->nrows > aggrrow->rowssize )
2916 {
2917 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
2918 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
2919 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
2920 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
2921 aggrrow->rowssize = newsize;
2922 }
2923 aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
2924 aggrrow->rowweights[i] = weight;
2925
2926 if( sidetype == -1 )
2927 {
2928 assert(!SCIPisInfinity(scip, -row->lhs));
2929 uselhs = TRUE;
2930 }
2931 else if( sidetype == 1 )
2932 {
2933 assert(!SCIPisInfinity(scip, row->rhs));
2934 uselhs = FALSE;
2935 }
2936 else
2937 {
2938 /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
2939 * If possible, use the side that leads to a positive slack value in the summation.
2940 */
2941 if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
2942 uselhs = TRUE;
2943 else
2944 uselhs = FALSE;
2945 }
2946 rowexact = SCIProwGetRowExact(row);
2947 if( !SCIProwExactHasFpRelax(rowexact) )
2948 {
2949 *success = FALSE;
2950 return SCIP_OKAY;
2951 }
2952 else if( SCIProwExactGetRowRhs(rowexact) != NULL && weight >= 0.0 )
2953 userow = SCIProwExactGetRowRhs(rowexact);
2954 else
2955 userow = row;
2956
2957 aggrrow->slacksign[i] = uselhs ? -1 : 1;
2958
2959 previousroundmode = SCIPintervalGetRoundingMode();
2960
2961 if( uselhs )
2962 {
2964 sideval = userow->lhs - userow->constant;
2965#ifdef SCIP_DISABLED_CODE
2966 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
2967 /* row is integral? round left hand side up */
2968 if( userow->integral )
2969 sideval = ceil(sideval)
2970#endif
2971 }
2972 else
2973 {
2975 sideval = userow->rhs - 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 right hand side down */
2979 if( userow->integral )
2980 sideval = floor(sideval);
2981#endif
2982 }
2983
2985 sidevalchg = QUAD_TO_DBL(aggrrow->rhs);
2986 sidevalchg += sideval * weight;
2987 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
2988
2989 /* add up coefficients */
2990 *success = TRUE;
2991 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, aggrrow->inds, aggrrow->vals, &aggrrow->nnz, userow, weight, &sidevalchg, success) );
2992
2993 sidevalchg += QUAD_TO_DBL(aggrrow->rhs);
2994 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
2995
2996 SCIPintervalSetRoundingMode(previousroundmode);
2997
2998 return SCIP_OKAY;
2999}
3000
3001/** Removes a given variable @p var from position @p pos the aggregation row and updates the right-hand side according
3002 * to sign of the coefficient, i.e., rhs -= coef * bound, where bound = lb if coef >= 0 and bound = ub, otherwise.
3003 *
3004 * @note: The choice of global or local bounds depend on the validity (global or local) of the aggregation row.
3005 *
3006 * @note: The list of non-zero indices will be updated by swapping the last non-zero index to @p pos.
3007 */
3009 SCIP* scip, /**< SCIP data structure */
3010 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3011 SCIP_VAR* var, /**< variable that should be removed */
3012 int pos, /**< position of the variable in the aggregation row */
3013 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
3014 )
3015{
3016 SCIP_Real QUAD(val);
3017 int v;
3018
3019 assert(valid != NULL);
3020 assert(pos >= 0);
3021
3022 v = aggrrow->inds[pos];
3023 assert(v == SCIPvarGetProbindex(var));
3024
3025 QUAD_ARRAY_LOAD(val, aggrrow->vals, v);
3026
3027 *valid = TRUE;
3028
3029 /* adjust left and right hand sides with max contribution */
3030 if( QUAD_TO_DBL(val) < 0.0 )
3031 {
3032 SCIP_Real ub = aggrrow->local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
3033
3034 if( SCIPisInfinity(scip, ub) )
3035 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
3036 else
3037 {
3038 SCIPquadprecProdQD(val, val, ub);
3039 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
3040 }
3041 }
3042 else
3043 {
3044 SCIP_Real lb = aggrrow->local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
3045
3046 if( SCIPisInfinity(scip, -lb) )
3047 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
3048 else
3049 {
3050 SCIPquadprecProdQD(val, val, lb);
3051 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
3052 }
3053 }
3054
3055 QUAD_ASSIGN(val, 0.0);
3056 QUAD_ARRAY_STORE(aggrrow->vals, v, val);
3057
3058 /* remove non-zero entry */
3059 --(aggrrow->nnz);
3060 aggrrow->inds[pos] = aggrrow->inds[aggrrow->nnz];
3061
3062 if( SCIPisInfinity(scip, QUAD_HI(aggrrow->rhs)) )
3063 *valid = FALSE;
3064}
3065
3066/** add the objective function with right-hand side @p rhs and scaled by @p scale to the aggregation row */
3068 SCIP* scip, /**< SCIP data structure */
3069 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3070 SCIP_Real rhs, /**< right-hand side of the artificial row */
3071 SCIP_Real scale /**< scalar */
3072 )
3073{
3074 SCIP_VAR** vars;
3075 SCIP_Real QUAD(val);
3076 int nvars;
3077
3078 assert(scip != NULL);
3079 assert(aggrrow != NULL);
3080
3081 vars = SCIPgetVars(scip);
3082 nvars = SCIPgetNVars(scip);
3083
3084 /* add all variables straight forward if the aggregation row is empty */
3085 if( aggrrow->nnz == 0 )
3086 {
3087 int i;
3088 for( i = 0; i < nvars; ++i )
3089 {
3090 assert(SCIPvarGetProbindex(vars[i]) == i);
3091
3092 /* skip all variables with zero objective coefficient */
3093 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
3094 continue;
3095
3096 QUAD_ASSIGN(val, scale * SCIPvarGetObj(vars[i])); /*lint !e665*/
3097 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
3098 aggrrow->inds[aggrrow->nnz++] = i;
3099 }
3100
3101 /* add right-hand side value */
3102 QUAD_ASSIGN(aggrrow->rhs, scale * rhs); /*lint !e665*/
3103 }
3104 else
3105 {
3106 int i;
3107 SCIP_Real QUAD(quadprod);
3108 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
3109 for( i = 0 ; i < nvars; ++i )
3110 {
3111 SCIP_Real varobj;
3112 assert(SCIPvarGetProbindex(vars[i]) == i);
3113
3114 /* skip all variables with zero objective coefficient */
3115 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
3116 continue;
3117
3118 QUAD_ARRAY_LOAD(val, aggrrow->vals, i); /* val = aggrrow->vals[i] */
3119
3120 if( QUAD_HI(val) == 0.0 )
3121 aggrrow->inds[aggrrow->nnz++] = i;
3122
3123 varobj = SCIPvarGetObj(vars[i]);
3124 SCIPquadprecProdDD(quadprod, scale, varobj);
3125 SCIPquadprecSumQQ(val, val, quadprod);
3126
3127 /* the value must not be exactly zero due to sparsity pattern */
3128 QUAD_HI(val) = NONZERO(QUAD_HI(val));
3129 assert(QUAD_HI(val) != 0.0);
3130
3131 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
3132 }
3133
3134 /* add right-hand side value */
3135 SCIPquadprecProdDD(quadprod, scale, rhs);
3136 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
3137 }
3138
3139 return SCIP_OKAY;
3140}
3141
3142/** add weighted constraint to the aggregation row */
3144 SCIP* scip, /**< SCIP data structure */
3145 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3146 int* inds, /**< variable problem indices in constraint to add to the aggregation row */
3147 SCIP_Real* vals, /**< values of constraint to add to the aggregation row */
3148 int len, /**< length of constraint to add to the aggregation row */
3149 SCIP_Real rhs, /**< right hand side of constraint to add to the aggregation row */
3150 SCIP_Real weight, /**< (positive) scale for adding given constraint to the aggregation row */
3151 int rank, /**< rank to use for given constraint */
3152 SCIP_Bool local /**< is constraint only valid locally */
3153 )
3154{
3155 SCIP_Real QUAD(quadprod);
3156 int i;
3157
3158 assert(weight >= 0.0);
3159 assert(!SCIPisInfinity(scip, REALABS(weight * rhs)));
3160
3161 /* update local flag */
3162 aggrrow->local = aggrrow->local || local;
3163
3164 /* update rank */
3165 aggrrow->rank = MAX(rank, aggrrow->rank);
3166
3167 /* add right hand side value */
3168 SCIPquadprecProdDD(quadprod, weight, rhs);
3169 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
3170
3171 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
3172 for( i = 0 ; i < len; ++i )
3173 {
3174 SCIP_Real QUAD(val);
3175 int probindex = inds[i];
3176
3177 QUAD_ARRAY_LOAD(val, aggrrow->vals, probindex); /* val = aggrrow->vals[probindex] */
3178
3179 if( QUAD_HI(val) == 0.0 )
3180 aggrrow->inds[aggrrow->nnz++] = probindex;
3181
3182 SCIPquadprecProdDD(quadprod, vals[i], weight);
3183 SCIPquadprecSumQQ(val, val, quadprod);
3184
3185 /* the value must not be exactly zero due to sparsity pattern */
3186 QUAD_HI(val) = NONZERO(QUAD_HI(val));
3187 assert(QUAD_HI(val) != 0.0);
3188
3189 QUAD_ARRAY_STORE(aggrrow->vals, probindex, val);
3190 }
3191
3192 return SCIP_OKAY;
3193}
3194
3195/** version for use in exact solving mode of SCIPaggrRowClear() */
3197 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3198 )
3199{
3200 int i;
3201
3202 /* in exact solving mode, we do not use quad precision, because we need to control the rounding mode; hence, we only
3203 * use and clear the first SCIPgetNVars() entries
3204 */
3205 for( i = 0; i < aggrrow->nnz; ++i )
3206 {
3207 aggrrow->vals[aggrrow->inds[i]] = 0.0;
3208 }
3209
3210 aggrrow->nnz = 0;
3211 aggrrow->nrows = 0;
3212 aggrrow->rank = 0;
3213 QUAD_ASSIGN(aggrrow->rhs, 0.0);
3214 aggrrow->local = FALSE;
3215}
3216
3217/** clear all entries int the aggregation row but don't free memory */
3219 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3220 )
3221{
3222 int i;
3223 SCIP_Real QUAD(tmp);
3224
3225 QUAD_ASSIGN(tmp, 0.0);
3226
3227 for( i = 0; i < aggrrow->nnz; ++i )
3228 {
3229 QUAD_ARRAY_STORE(aggrrow->vals, aggrrow->inds[i], tmp);
3230 }
3231
3232 aggrrow->nnz = 0;
3233 aggrrow->nrows = 0;
3234 aggrrow->rank = 0;
3235 QUAD_ASSIGN(aggrrow->rhs, 0.0);
3236 aggrrow->local = FALSE;
3237}
3238
3239/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
3240 *
3241 * @return the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
3242 */
3244 SCIP* scip, /**< SCIP data structure */
3245 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3246 )
3247{
3248 return calcEfficacyNormQuad(scip, aggrrow->vals, aggrrow->inds, aggrrow->nnz);
3249}
3250
3251/** adds one row to the aggregation row
3252 *
3253 * @note this method differs from SCIPaggrRowAddRow() by providing some additional parameters required for
3254 * SCIPaggrRowSumRows()
3255 */
3256static
3258 SCIP* scip, /**< SCIP data structure */
3259 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3260 SCIP_ROW* row, /**< the row to add */
3261 SCIP_Real weight, /**< weight of row to add */
3262 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
3263 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
3264 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
3265 int maxaggrlen, /**< maximal length of aggregation row */
3266 SCIP_Bool* rowtoolong /**< is the aggregated row too long */
3267 )
3268{
3269 SCIP_Real QUAD(quadprod);
3270 SCIP_Real sideval;
3271 SCIP_Bool uselhs;
3272 int i;
3273
3274 assert( rowtoolong != NULL );
3275 *rowtoolong = FALSE;
3276
3277 if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
3278 {
3279 return SCIP_OKAY;
3280 }
3281
3282 if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
3283 {
3285
3286 if( stat == SCIP_BASESTAT_LOWER )
3287 {
3288 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
3289 uselhs = TRUE;
3290 }
3291 else if( stat == SCIP_BASESTAT_UPPER )
3292 {
3293 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
3294 uselhs = FALSE;
3295 }
3296 else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
3297 uselhs = TRUE;
3298 else
3299 uselhs = FALSE;
3300 }
3301 else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
3302 uselhs = TRUE;
3303 else
3304 uselhs = FALSE;
3305
3306 if( uselhs )
3307 {
3308 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
3309
3310 if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
3311 return SCIP_OKAY;
3312
3313 sideval = row->lhs - row->constant;
3314 /* row is integral? round left hand side up */
3315 if( row->integral )
3316 sideval = SCIPceil(scip, sideval);
3317 }
3318 else
3319 {
3320 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
3321
3322 if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
3323 return SCIP_OKAY;
3324
3325 sideval = row->rhs - row->constant;
3326 /* row is integral? round right hand side down */
3327 if( row->integral )
3328 sideval = SCIPfloor(scip, sideval);
3329 }
3330
3331 /* add right hand side, update rank and local flag */
3332 SCIPquadprecProdDD(quadprod, sideval, weight);
3333 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
3334 aggrrow->rank = MAX(aggrrow->rank, row->rank);
3335 aggrrow->local = aggrrow->local || row->local;
3336
3337 /* ensure the array for storing the row information is large enough */
3338 i = aggrrow->nrows++;
3339 if( aggrrow->nrows > aggrrow->rowssize )
3340 {
3341 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
3342 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
3343 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
3344 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
3345 aggrrow->rowssize = newsize;
3346 }
3347
3348 /* add information of addditional row */
3349 aggrrow->rowsinds[i] = row->lppos;
3350 aggrrow->rowweights[i] = weight;
3351 aggrrow->slacksign[i] = uselhs ? -1 : 1;
3352
3353 /* add up coefficients */
3354 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
3355
3356 /* check if row is too long now */
3357 if( aggrrow->nnz > maxaggrlen )
3358 *rowtoolong = TRUE;
3359
3360 return SCIP_OKAY;
3361}
3362
3363/** adds one row to the aggregation row
3364 *
3365 * @note this method differs from SCIPaggrRowAddRowSafely() by providing some additional parameters required for
3366 * SCIPaggrRowSumRows()
3367 *
3368 * @note this method is the variant of addOneRow() that is safe to use in exact solving mode
3369 */
3370static
3372 SCIP* scip, /**< SCIP data structure */
3373 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3374 SCIP_ROW* row, /**< the row to add */
3375 SCIP_Real weight, /**< weight of row to add */
3376 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
3377 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
3378 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
3379 int maxaggrlen, /**< maximal length of aggregation row */
3380 SCIP_Bool* rowtoolong, /**< is the aggregated row too long */
3381 SCIP_Bool* rowused, /**< was the row really added? */
3382 SCIP_Bool* success, /**< was the row added successfully? */
3383 SCIP_Bool* lhsused /**< was the lhs or the rhs of the row used? */
3384 )
3385{
3386 SCIP_Real sideval;
3387 SCIP_Real sidevalchg;
3388 SCIP_Bool uselhs;
3389 SCIP_ROW* userow;
3390 SCIP_ROWEXACT* rowexact;
3391 SCIP_ROUNDMODE previousroundmode;
3392 int i;
3393
3394 assert(SCIPisExact(scip));
3395 assert(rowtoolong != NULL);
3396 *rowtoolong = FALSE;
3397 *rowused = FALSE;
3398
3399 if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
3400 {
3401 return SCIP_OKAY;
3402 }
3403
3404 if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
3405 {
3407
3408 if( stat == SCIP_BASESTAT_LOWER )
3409 {
3410 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
3411 uselhs = TRUE;
3412 }
3413 else if( stat == SCIP_BASESTAT_UPPER )
3414 {
3415 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
3416 uselhs = FALSE;
3417 }
3418 else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
3419 uselhs = TRUE;
3420 else
3421 uselhs = FALSE;
3422 }
3423 else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
3424 uselhs = TRUE;
3425 else
3426 uselhs = FALSE;
3427
3428 rowexact = SCIProwGetRowExact(row);
3429 if( !SCIProwExactHasFpRelax(rowexact) )
3430 {
3431 *success = FALSE;
3432 return SCIP_OKAY;
3433 }
3434 else if( SCIProwExactGetRowRhs(rowexact) != NULL && weight >= 0.0 )
3435 userow = SCIProwExactGetRowRhs(rowexact);
3436 else
3437 userow = row;
3438
3439 previousroundmode = SCIPintervalGetRoundingMode();
3440
3441 if( uselhs )
3442 {
3443 *lhsused = TRUE;
3444 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
3445
3446 if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
3447 return SCIP_OKAY;
3448
3450
3451 sideval = userow->lhs - userow->constant;
3452#ifdef SCIP_DISABLED_CODE
3453 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
3454 /* row is integral? round left hand side up */
3455 if( userow->integral )
3456 sideval = ceil(sideval);
3457#endif
3458 }
3459 else
3460 {
3461 *lhsused = FALSE;
3462 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
3463
3464 if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
3465 return SCIP_OKAY;
3466
3468
3469 sideval = userow->rhs - userow->constant;
3470#ifdef SCIP_DISABLED_CODE
3471 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
3472 /* row is integral? round right hand side down */
3473 if( userow->integral )
3474 sideval = floor(sideval);
3475#endif
3476 }
3477
3479
3480 sidevalchg = QUAD_TO_DBL(aggrrow->rhs);
3481 sidevalchg += sideval * weight;
3482 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
3483
3484 aggrrow->rank = MAX(aggrrow->rank, userow->rank);
3485 aggrrow->local = aggrrow->local || userow->local;
3486
3487 /* ensure the array for storing the row information is large enough */
3488 i = aggrrow->nrows++;
3489 *rowused = TRUE;
3490 if( aggrrow->nrows > aggrrow->rowssize )
3491 {
3492 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
3493 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
3494 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
3495 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
3496 aggrrow->rowssize = newsize;
3497 }
3498
3499 /* add information of addditional row */
3500 aggrrow->rowsinds[i] = row->lppos;
3501 aggrrow->rowweights[i] = weight;
3502 aggrrow->slacksign[i] = uselhs ? -1 : 1;
3503
3504 /* add up coefficients */
3505 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, aggrrow->inds, aggrrow->vals, &aggrrow->nnz, userow, weight, &sidevalchg, success) );
3506
3507 sidevalchg += QUAD_TO_DBL(aggrrow->rhs);
3508 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
3509
3510 /* check if row is too long now */
3511 if( aggrrow->nnz > maxaggrlen )
3512 *rowtoolong = TRUE;
3513
3514 SCIPintervalSetRoundingMode(previousroundmode);
3515
3516 return SCIP_OKAY;
3517}
3518
3519/** aggregate rows using the given weights; the current content of the aggregation row, \p aggrrow, is overwritten
3520 *
3521 * @note this method is safe for usage in exact solving mode
3522 */
3524 SCIP* scip, /**< SCIP data structure */
3525 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3526 SCIP_Real* weights, /**< row weights in row summation */
3527 int* rowinds, /**< array to store indices of non-zero entries of the weights array, or NULL */
3528 int nrowinds, /**< number of non-zero entries in weights array, -1 if rowinds is NULL */
3529 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
3530 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
3531 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
3532 int maxaggrlen, /**< maximal length of aggregation row */
3533 SCIP_Bool* valid /**< is the aggregation valid */
3534 )
3535{
3536 SCIP_AGGRROW* certificaterow = NULL;
3537 SCIP_ROW** rows;
3538 SCIP_ROW** usedrows = NULL;
3539 SCIP_ROW** negslackrows = NULL;
3540 SCIP_VAR** vars;
3541 SCIP_Real* usedweights = NULL;
3542 SCIP_Real* negslackweights = NULL;
3543 int nrows;
3544 int nvars;
3545 int k;
3546 int nusedrows;
3547 int nnegslackrows;
3548 SCIP_Bool rowtoolong;
3549 SCIP_Bool rowused, rowusedcert, lhsused;
3550
3551 assert( scip != NULL );
3552 assert( aggrrow != NULL );
3553 assert( valid != NULL );
3554
3555 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
3556 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
3557
3558 if( SCIPisExact(scip) )
3559 SCIPaggrRowClearSafely(aggrrow);
3560 else
3561 SCIPaggrRowClear(aggrrow);
3562 *valid = TRUE;
3563 lhsused = FALSE;
3564 nusedrows = 0;
3565 nnegslackrows = 0;
3566
3567 SCIPdebugMessage("Summing up %d rows in aggrrow \n", nrowinds);
3568
3569 if( SCIPisCertified(scip) )
3570 {
3571 SCIP_CALL( SCIPallocBufferArray(scip, &usedrows, nrows) );
3572 SCIP_CALL( SCIPallocBufferArray(scip, &usedweights, nrows) );
3573 SCIP_CALL( SCIPallocBufferArray(scip, &negslackrows, nrows) );
3574 SCIP_CALL( SCIPallocBufferArray(scip, &negslackweights, nrows) );
3575 SCIP_CALL( SCIPaggrRowCreate(scip, &certificaterow) );
3576 }
3577
3578 if( rowinds != NULL && nrowinds > -1 )
3579 {
3580 for( k = 0; k < nrowinds; ++k )
3581 {
3582 if( !SCIPisExact(scip) )
3583 {
3584 SCIP_CALL( addOneRow(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
3585
3586 if( rowtoolong )
3587 *valid = FALSE;
3588 }
3589 else /*lint --e{644}*/
3590 {
3591 SCIPdebugMessage("Adding %g times row: ", weights[rowinds[k]]);
3592 SCIPdebug(SCIPprintRow(scip, rows[rowinds[k]], NULL));
3593 SCIP_CALL( addOneRowSafely(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal,
3594 negslack, maxaggrlen, &rowtoolong, &rowused, valid, &lhsused) );
3595
3596 if( rowtoolong )
3597 *valid = FALSE;
3598
3599 if( !(*valid) )
3600 break;
3601
3602 if( certificaterow != NULL )
3603 {
3604 assert(usedrows != NULL);
3605 assert(usedweights != NULL);
3606 assert(negslackrows != NULL);
3607 assert(negslackweights != NULL);
3608
3609 SCIP_ROW* row = rows[rowinds[k]];
3610 SCIP_Bool integral = FALSE;
3611
3612 /* just exclude the negative continuous slacks for the certificate rows */
3613 if( row->integral &&
3614 ((!lhsused && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant)) ||
3616 {
3617 SCIPdebugMessage("row has integral slack\n");
3618 rowusedcert = FALSE;
3619 integral = TRUE;
3620 }
3621 else
3622 {
3623 /* the certificate row may exceed the limit maxaggrlen */
3624 SCIP_CALL( addOneRowSafely(scip, certificaterow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis,
3625 allowlocal, 0, nvars, &rowtoolong, &rowusedcert, valid, &lhsused) );
3626 assert(!rowtoolong);
3627 }
3628 if( rowusedcert )
3629 {
3630 usedrows[nusedrows] = rows[rowinds[k]];
3631 usedweights[nusedrows] = weights[rowinds[k]];
3632 nusedrows++;
3633 }
3634 if( rowused && !rowusedcert && !integral )
3635 {
3636 SCIPdebugMessage("row has negative continous slack\n");
3637 assert( (lhsused && weights[rowinds[k]] >= 0) || ((!lhsused) && weights[rowinds[k]] <= 0) || row->integral );
3638 negslackrows[nnegslackrows] = rows[rowinds[k]];
3639 negslackweights[nnegslackrows] = -weights[rowinds[k]];
3640 nnegslackrows++;
3641 }
3642 }
3643 }
3644
3645 if( !(*valid) )
3646 break;
3647 }
3648 }
3649 else
3650 {
3651 for( k = 0; k < nrows; ++k )
3652 {
3653 if( weights[k] != 0.0 )
3654 {
3655 if( !SCIPisExact(scip) )
3656 {
3657 SCIP_CALL( addOneRow(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
3658
3659 if( rowtoolong )
3660 *valid = FALSE;
3661 }
3662 else
3663 {
3664 SCIPdebugMessage("Adding %g times row: ", weights[k]);
3665 SCIPdebug(SCIPprintRow(scip, rows[k], NULL));
3666 SCIP_CALL( addOneRowSafely(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack,
3667 maxaggrlen, &rowtoolong, &rowused, valid, &lhsused) );
3668
3669 if( rowtoolong )
3670 *valid = FALSE;
3671
3672 if( !(*valid) )
3673 break;
3674
3675 if( certificaterow != NULL )
3676 {
3677 assert(usedrows != NULL);
3678 assert(usedweights != NULL);
3679 assert(negslackrows != NULL);
3680 assert(negslackweights != NULL);
3681
3682 SCIP_ROW* row = rows[k];
3683 SCIP_Bool integral = FALSE;
3684
3685 /* just exclude the negative continuous slacks for the certificate rows */
3686 if( row->integral &&
3687 ((!lhsused && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant)) ||
3689 {
3690 rowusedcert = FALSE;
3691 SCIPdebugMessage("row has integral slack\n");
3692 integral = TRUE;
3693 }
3694 else
3695 {
3696 /* the certificate row may exceed the limit maxaggrlen */
3697 SCIP_CALL( addOneRowSafely(scip, certificaterow, rows[k], weights[k], sidetypebasis, allowlocal, 0,
3698 nvars, &rowtoolong, &rowusedcert, valid, &lhsused) );
3699 assert(!rowtoolong);
3700 }
3701 if( rowusedcert )
3702 {
3703 usedrows[nusedrows] = rows[k];
3704 usedweights[nusedrows] = weights[k];
3705 nusedrows++;
3706 }
3707 if( rowused && !rowusedcert && !integral )
3708 {
3709 SCIPdebugMessage("row has negative continous slack\n");
3710 assert( (lhsused && weights[k] >= 0) || ((!lhsused) && weights[k] <= 0) || row->integral );
3711 negslackrows[nnegslackrows] = rows[k];
3712 negslackweights[nnegslackrows] = -weights[k];
3713 nnegslackrows++;
3714 }
3715 }
3716 }
3717
3718 if( !(*valid) )
3719 break;
3720 }
3721 }
3722 }
3723
3724 if( *valid )
3725 {
3726 SCIPaggrRowRemoveZeros(scip, aggrrow, FALSE, valid);
3727
3728 if( certificaterow != NULL )
3729 {
3730 SCIPaggrRowRemoveZeros(scip, certificaterow, FALSE, valid);
3731 SCIP_CALL( SCIPaddCertificateAggrInfo(scip, certificaterow, usedrows, usedweights, certificaterow->nrows,
3732 negslackrows, negslackweights, nnegslackrows) );
3733 }
3734 }
3735
3736 if( certificaterow != NULL )
3737 {
3738 SCIPaggrRowFree(scip, &certificaterow);
3739 SCIPfreeBufferArray(scip, &negslackweights);
3740 SCIPfreeBufferArray(scip, &negslackrows);
3741 SCIPfreeBufferArray(scip, &usedweights);
3742 SCIPfreeBufferArray(scip, &usedrows);
3743 }
3744
3745 return SCIP_OKAY;
3746}
3747
3748/** checks for cut redundancy and performs activity based coefficient tightening;
3749 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
3750 * to remove small coefficients (relative to the maximum absolute coefficient)
3751 */
3752static
3754 SCIP* scip, /**< SCIP data structure */
3755 SCIP_Bool cutislocal, /**< is the cut a local cut */
3756 int* cutinds, /**< variable problem indices of non-zeros in cut */
3757 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
3758 int* nnz, /**< number non-zeros coefficients of cut */
3759 SCIP_Real* cutrhs, /**< right hand side of cut */
3760 SCIP_Bool* success /**< pointer to return whether post-processing was successful or cut is redundant */
3761 )
3762{
3763 int i;
3764 SCIP_Bool redundant;
3765 SCIP_Real maxcoef;
3766 SCIP_Real minallowedcoef;
3767 SCIP_Real QUAD(rhs);
3768
3769 assert(scip != NULL);
3770 assert(cutinds != NULL);
3771 assert(cutcoefs != NULL);
3772 assert(cutrhs != NULL);
3773 assert(success != NULL);
3774
3775 *success = FALSE;
3776
3777 QUAD_ASSIGN(rhs, *cutrhs);
3778
3779 if( removeZeros(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz) )
3780 {
3781 /* right hand side was changed to infinity -> cut is redundant */
3782 return SCIP_OKAY;
3783 }
3784
3785 if( *nnz == 0 )
3786 return SCIP_OKAY;
3787
3788 SCIP_CALL( cutTightenCoefs(scip, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz, &redundant) );
3789
3790 if( redundant )
3791 {
3792 /* cut is redundant */
3793 return SCIP_OKAY;
3794 }
3795
3796 maxcoef = 0.0;
3797 for( i = 0; i < *nnz; ++i )
3798 {
3799 SCIP_Real absval = REALABS(cutcoefs[cutinds[i]]);
3800 maxcoef = MAX(absval, maxcoef);
3801 }
3802
3803 maxcoef /= scip->set->sepa_maxcoefratio;
3804 minallowedcoef = SCIPsumepsilon(scip);
3805 minallowedcoef = MAX(minallowedcoef, maxcoef);
3806
3807 *success = ! removeZeros(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz);
3808 *cutrhs = QUAD_TO_DBL(rhs);
3809
3810 return SCIP_OKAY;
3811}
3812
3813
3814/** checks for cut redundancy and performs activity based coefficient tightening;
3815 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
3816 * to remove small coefficients (relative to the maximum absolute coefficient).
3817 * The cutcoefs must be a quad precision array, i.e. allocated with size
3818 * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
3819 * macros.
3820 */
3821static
3823 SCIP* scip, /**< SCIP data structure */
3824 SCIP_Bool cutislocal, /**< is the cut a local cut */
3825 int* cutinds, /**< variable problem indices of non-zeros in cut */
3826 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
3827 int* nnz, /**< number non-zeros coefficients of cut */
3828 QUAD(SCIP_Real* cutrhs), /**< right hand side of cut */
3829 SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
3830 )
3831{
3832 int i;
3833 SCIP_Bool redundant;
3834 SCIP_Real maxcoef;
3835 SCIP_Real minallowedcoef;
3836
3837 assert(scip != NULL);
3838 assert(cutinds != NULL);
3839 assert(cutcoefs != NULL);
3840 assert(QUAD_HI(cutrhs) != NULL);
3841 assert(success != NULL);
3842
3843 *success = FALSE;
3844
3845 if( removeZerosQuad(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz) )
3846 {
3847 /* right hand side was changed to infinity -> cut is redundant */
3848 return SCIP_OKAY;
3849 }
3850
3851 if( *nnz == 0 )
3852 return SCIP_OKAY;
3853
3854 SCIP_CALL( cutTightenCoefsQuad(scip, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz, &redundant) );
3855 if( redundant )
3856 {
3857 /* cut is redundant */
3858 return SCIP_OKAY;
3859 }
3860
3861 maxcoef = 0.0;
3862 for( i = 0; i < *nnz; ++i )
3863 {
3864 SCIP_Real abscoef;
3865 SCIP_Real QUAD(coef);
3866 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]); /* coef = cutcoefs[cutinds[i]] */
3867 abscoef = REALABS(QUAD_TO_DBL(coef));
3868 maxcoef = MAX(abscoef, maxcoef);
3869 }
3870
3871 maxcoef /= scip->set->sepa_maxcoefratio;
3872 minallowedcoef = SCIPsumepsilon(scip);
3873 minallowedcoef = MAX(minallowedcoef, maxcoef);
3874
3875 *success = ! removeZerosQuad(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz);
3876
3877 return SCIP_OKAY;
3878}
3879
3880/** checks for cut redundancy and performs activity based coefficient tightening;
3881 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
3882 * to remove small coefficients (relative to the maximum absolute coefficient).
3883 * The cutcoefs must be a quad precision array, i.e. allocated with size
3884 * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
3885 * macros.
3886 */
3887static
3889 SCIP* scip, /**< SCIP data structure */
3890 SCIP_Bool cutislocal, /**< is the cut a local cut */
3891 int* cutinds, /**< variable problem indices of non-zeros in cut */
3892 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
3893 int* nnz, /**< number non-zeros coefficients of cut */
3894 SCIP_Real* cutrhs, /**< right hand side of cut */
3895 SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
3896 )
3897{
3898 int i;
3899 SCIP_Bool redundant;
3900 SCIP_Real maxcoef;
3901 SCIP_Real minallowedcoef;
3902
3903 assert(SCIPisExact(scip));
3904
3905 assert(scip != NULL);
3906 assert(cutinds != NULL);
3907 assert(cutcoefs != NULL);
3908 assert(cutrhs != NULL);
3909 assert(success != NULL);
3910
3911 *success = FALSE;
3912
3913 if( removeZerosSafely(scip, SCIPfeastol(scip), cutcoefs, cutrhs, cutinds, nnz) )
3914 {
3915 /* right hand side was changed to infinity -> cut is redundant */
3916 return SCIP_OKAY;
3917 }
3918
3919 if( *nnz == 0 )
3920 return SCIP_OKAY;
3921
3922 SCIP_CALL( cutTightenCoefsSafely(scip, cutislocal, cutcoefs, cutrhs, cutinds, nnz, &redundant) );
3923 if( redundant )
3924 {
3925 /* cut is redundant */
3926 return SCIP_OKAY;
3927 }
3928
3929 maxcoef = 0.0;
3930 for( i = 0; i < *nnz; ++i )
3931 {
3932 SCIP_Real abscoef;
3933 SCIP_Real coef;
3934 coef = cutcoefs[cutinds[i]];
3935 abscoef = REALABS(coef);
3936 maxcoef = MAX(abscoef, maxcoef);
3937 }
3938
3939 maxcoef /= scip->set->sepa_maxcoefratio;
3940 minallowedcoef = SCIPsumepsilon(scip);
3941 minallowedcoef = MAX(minallowedcoef, maxcoef);
3942
3943 *success = ! removeZerosSafely(scip, minallowedcoef, cutcoefs, cutrhs, cutinds, nnz);
3944
3945 return SCIP_OKAY;
3946}
3947
3948/** removes almost zero entries from the aggregation row. */
3950 SCIP* scip, /**< SCIP datastructure */
3951 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
3952 SCIP_Bool useglbbounds, /**< consider global bound although the cut is local? */
3953 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
3954 )
3955{
3956 assert(aggrrow != NULL);
3957 assert(valid != NULL);
3958
3959 if( SCIPisExact(scip) )
3960 {
3961 SCIP_Real rhs;
3962 rhs = QUAD_TO_DBL(aggrrow->rhs);
3963 *valid = !removeZerosSafely(scip, SCIPsumepsilon(scip), aggrrow->vals, &rhs, aggrrow->inds, &aggrrow->nnz);
3964 QUAD_ASSIGN(aggrrow->rhs, rhs);
3965 return;
3966 }
3967
3968 *valid = ! removeZerosQuad(scip, SCIPsumepsilon(scip), useglbbounds ? FALSE : aggrrow->local, aggrrow->vals,
3969 QUAD(&aggrrow->rhs), aggrrow->inds, &aggrrow->nnz);
3970}
3971
3972/** get number of aggregated rows */
3974 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3975 )
3976{
3977 assert(aggrrow != NULL);
3978
3979 return aggrrow->nrows;
3980}
3981
3982/** get array with lp positions of rows used in aggregation */
3984 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3985 )
3986{
3987 assert(aggrrow != NULL);
3988 assert(aggrrow->rowsinds != NULL || aggrrow->nrows == 0);
3989
3990 return aggrrow->rowsinds;
3991}
3992
3993/** get array with weights of aggregated rows */
3995 SCIP_AGGRROW* aggrrow /**< the aggregation row */
3996 )
3997{
3998 assert(aggrrow != NULL);
3999 assert(aggrrow->rowweights != NULL || aggrrow->nrows == 0);
4000
4001 return aggrrow->rowweights;
4002}
4003
4004/** checks whether a given row has been added to the aggregation row */
4006 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
4007 SCIP_ROW* row /**< row for which it is checked whether it has been added to the aggregation */
4008 )
4009{
4010 int i;
4011 int rowind;
4012
4013 assert(aggrrow != NULL);
4014 assert(row != NULL);
4015
4016 rowind = SCIProwGetLPPos(row);
4017
4018 for( i = 0; i < aggrrow->nrows; ++i )
4019 {
4020 if( aggrrow->rowsinds[i] == rowind )
4021 return TRUE;
4022 }
4023
4024 return FALSE;
4025}
4026
4027/** gets the array of corresponding variable problem indices for each non-zero in the aggregation row */
4029 SCIP_AGGRROW* aggrrow /**< aggregation row */
4030 )
4031{
4032 assert(aggrrow != NULL);
4033
4034 return aggrrow->inds;
4035}
4036
4037/** gets the number of non-zeros in the aggregation row */
4039 SCIP_AGGRROW* aggrrow /**< aggregation row */
4040 )
4041{
4042 assert(aggrrow != NULL);
4043
4044 return aggrrow->nnz;
4045}
4046
4047/** gets the rank of the aggregation row */
4049 SCIP_AGGRROW* aggrrow /**< aggregation row */
4050 )
4051{
4052 assert(aggrrow != NULL);
4053
4054 return aggrrow->rank;
4055}
4056
4057/** checks if the aggregation row is only valid locally */
4059 SCIP_AGGRROW* aggrrow /**< aggregation row */
4060 )
4061{
4062 assert(aggrrow != NULL);
4063
4064 return aggrrow->local;
4065}
4066
4067/** gets the right hand side of the aggregation row */
4069 SCIP_AGGRROW* aggrrow /**< aggregation row */
4070 )
4071{
4072 assert(aggrrow != NULL);
4073
4074 return QUAD_TO_DBL(aggrrow->rhs);
4075}
4076
4077/* =========================================== c-MIR =========================================== */
4078
4079#define MAXCMIRSCALE 1e+6 /**< maximal scaling (scale/(1-f0)) allowed in c-MIR calculations */
4080
4081/* In order to derive cuts, we partition the variable array up in (not necessarily contiguous) sections.
4082 * The only requirement we place on these sections is that section i can only have variable bounds variables whose section
4083 * is strictly greater than i. This way, we can process the variable array in a 'linear' manner. */
4084
4085/* @todo maintain a DAG for used varbounds and use topological ordering instead, this would also allow
4086 * variable bounds on variables of the same section to be used */
4087
4088#define NSECTIONS 6
4089
4090typedef struct MIR_Data
4091{
4092 int totalnnz; /* The total number of nonzeros in all of the sections */
4093 int* secindices[NSECTIONS]; /* The indices of the variables belonging to the section */
4094 int secnnz[NSECTIONS]; /* The number of nonzero indices in the section */
4095
4096 SCIP_Bool isenfint[NSECTIONS];/**< Does the section have an integrality constraint? */
4097 SCIP_Bool isimplint[NSECTIONS];/**< Is the section implied integer variables? */
4098
4099 /* Settings for cut derivation, per section */
4100 int usevbds[NSECTIONS]; /**< Should variable bound substitution be done for this section? */
4101
4102 /* Problem data that we reuse often */
4103 SCIP_VAR** vars; /**< pointer to SCIPs variable array */
4104 int nvars; /**< total number of variables */
4105 int nbinvars; /**< total number of non-implint binary variables */
4106 int nintvars; /**< total number of non-implint integer variables */
4107 int nbinimplvars; /**< total number of implint binary variables */
4108 int nintimplvars; /**< total number of implint integer variables */
4109 int ncontimplvars; /**< total number of implint continuous variables */
4110 int ncontvars; /**< total number of non-implied continuous variables */
4111
4112 SCIP_Real* cutcoefs; /**< working cut indices value array */
4113 SCIP_Real QUAD(cutrhs); /**< the working right hand side of the cut*/
4114
4115 int* cutinds; /**< working cut variable problem index array */
4116 int ncutinds; /**< number of values in the working cut variable problem index array */
4118
4119/** Returns the section of a variable.
4120 *
4121 * For now, this is equal to the variable type section of the variable in the problem.
4122 */
4123static
4125 MIR_DATA* data, /**< The MIR separation data */
4126 int probindex /**< Problem index of a variable */
4127 )
4128{
4129 int limit;
4130
4131 assert(data != NULL);
4132
4133 limit = data->nvars - data->ncontvars;
4134 if( probindex >= limit )
4135 return 0;
4136
4137 limit -= data->ncontimplvars;
4138 if( probindex >= limit )
4139 return 1;
4140
4141 limit -= data->nintimplvars;
4142 if( probindex >= limit )
4143 return 2;
4144
4145 limit -= data->nbinimplvars;
4146 if( probindex >= limit )
4147 return 3;
4148
4149 limit -= data->nintvars;
4150 if( probindex >= limit )
4151 return 4;
4152
4153 assert(limit == data->nbinvars);
4154
4155 return 5;
4156}
4157
4158/** finds the best lower bound of the variable to use for MIR transformation.
4159 *
4160 * Currently, we use a slightly different function for the exact MIR cuts than for the normal MIR cuts due to differences
4161 * in how the codes can handle variable bound substitution. This function can only be used with the safe MIR code. */
4162/* @todo make behavior identical to the unsafe MIR cut computation */
4163static
4165 SCIP* scip, /**< SCIP data structure */
4166 SCIP_VAR* var, /**< problem variable */
4167 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4168 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4169 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4170 SCIP_Real* bestlb, /**< pointer to store best bound value */
4171 SCIP_Real* simplebound, /**< pointer to store simple bound value */
4172 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4173 )
4174{
4175 assert(bestlb != NULL);
4176 assert(bestlbtype != NULL);
4177 assert(usevbds >= 0 && usevbds <= 2);
4178
4179 *bestlb = SCIPvarGetLbGlobal(var);
4180 *bestlbtype = -1;
4181
4182 if( allowlocal )
4183 {
4184 SCIP_Real loclb;
4185
4186 loclb = SCIPvarGetLbLocal(var);
4187 if( SCIPisGT(scip, loclb, *bestlb) )
4188 {
4189 *bestlb = loclb;
4190 *bestlbtype = -2;
4191 }
4192 }
4193
4194 *simplebound = *bestlb;
4195
4196 if( usevbds && !SCIPvarIsIntegral(var) )
4197 {
4198 SCIP_Real bestvlb;
4199 int bestvlbidx;
4200
4201 SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
4202 if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
4203 {
4204 SCIP_VAR** vlbvars;
4205 SCIP_VAR* vlbvar;
4206
4207 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4208 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
4209 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
4210 */
4211 vlbvars = SCIPvarGetVlbVars(var);
4212 assert(vlbvars != NULL);
4213 vlbvar = vlbvars[bestvlbidx];
4214 assert(vlbvar != NULL);
4215 if( ( usevbds == 2 || ( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY
4216 && !SCIPvarIsImpliedIntegral(vlbvar) ) )
4217 && SCIPvarGetProbindex(vlbvar) < SCIPvarGetProbindex(var) )
4218 {
4219 *bestlb = bestvlb;
4220 *bestlbtype = bestvlbidx;
4221 }
4222 }
4223 }
4224
4225 return SCIP_OKAY;
4226}
4227
4228/** finds the best upper bound of the variable to use for MIR transformation.
4229 * currently, we use a slightly different function for the exact MIR cuts than for the normal MIR cuts due to differences
4230 * in how the codes can handle variable bound substitution. This function can only be used with the safe MIR code. */
4231/* @todo make behavior identical to the unsafe MIR cut computation */
4232static
4234 SCIP* scip, /**< SCIP data structure */
4235 SCIP_VAR* var, /**< problem variable */
4236 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4237 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4238 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4239 SCIP_Real* bestub, /**< pointer to store best bound value */
4240 SCIP_Real* simplebound, /**< pointer to store simple bound */
4241 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4242 )
4243{
4244 assert(bestub != NULL);
4245 assert(bestubtype != NULL);
4246
4247 *bestub = SCIPvarGetUbGlobal(var);
4248 *bestubtype = -1;
4249
4250 if( allowlocal )
4251 {
4252 SCIP_Real locub;
4253
4254 locub = SCIPvarGetUbLocal(var);
4255 if( SCIPisLT(scip, locub, *bestub) )
4256 {
4257 *bestub = locub;
4258 *bestubtype = -2;
4259 }
4260 }
4261
4262 *simplebound = *bestub;
4263
4264 if( usevbds && !SCIPvarIsIntegral(var) )
4265 {
4266 SCIP_Real bestvub;
4267 int bestvubidx;
4268
4269 SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
4270 if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
4271 {
4272 SCIP_VAR** vubvars;
4273 SCIP_VAR* vubvar;
4274
4275 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4276 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
4277 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
4278 */
4279 vubvars = SCIPvarGetVubVars(var);
4280 assert(vubvars != NULL);
4281 vubvar = vubvars[bestvubidx];
4282 assert(vubvar != NULL);
4283 if( ( usevbds == 2 || ( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY
4284 && !SCIPvarIsImpliedIntegral(vubvar) ) )
4285 && SCIPvarGetProbindex(vubvar) < SCIPvarGetProbindex(var) )
4286 {
4287 *bestub = bestvub;
4288 *bestubtype = bestvubidx;
4289 }
4290 }
4291 }
4292
4293 return SCIP_OKAY;
4294}
4295
4296/** determine the best bounds with respect to the given solution for complementing the given variable */
4297/* @todo make behavior identical to the unsafe MIR cut computation */
4298static
4300 SCIP* scip, /**< SCIP data structure */
4301 SCIP_VAR* var, /**< variable to determine best bound for */
4302 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4303 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
4304 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4305 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4306 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
4307 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
4308 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
4309 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
4310 * NULL for using closest bound for all variables */
4311 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
4312 * NULL for using closest bound for all variables */
4313 SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
4314 SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
4315 int* bestlbtype, /**< pointer to store type of the best lower bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
4316 int* bestubtype, /**< pointer to store type of best upper bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
4317 SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
4318 SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
4319 )
4320{
4321 SCIP_Real simplelb;
4322 SCIP_Real simpleub;
4323 int v;
4324
4325 v = SCIPvarGetProbindex(var);
4326
4327 /* check if the user specified a bound to be used */
4328 if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
4329 {
4330 assert(!SCIPvarIsIntegral(var) || boundsfortrans[v] == -2 || boundsfortrans[v] == -1);
4331 assert(boundtypesfortrans != NULL);
4332
4333 /* user has explicitly specified a bound to be used */
4334 if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
4335 {
4336 /* user wants to use lower bound */
4337 *bestlbtype = boundsfortrans[v];
4338 if( *bestlbtype == -1 )
4339 *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
4340 else if( *bestlbtype == -2 )
4341 *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
4342 else
4343 {
4344 SCIP_VAR** vlbvars;
4345 SCIP_Real* vlbcoefs;
4346 SCIP_Real* vlbconsts;
4347 int k;
4348
4349 assert(!ignoresol);
4350
4351 /* use the given variable lower bound */
4352 vlbvars = SCIPvarGetVlbVars(var);
4353 vlbcoefs = SCIPvarGetVlbCoefs(var);
4354 vlbconsts = SCIPvarGetVlbConstants(var);
4355 k = boundsfortrans[v];
4356 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
4357 assert(vlbvars != NULL);
4358 assert(vlbcoefs != NULL);
4359 assert(vlbconsts != NULL);
4360
4361 *bestlb = vlbcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[k]) : SCIPgetSolVal(scip, sol, vlbvars[k])) + vlbconsts[k];
4362 }
4363
4364 assert(!SCIPisInfinity(scip, - *bestlb));
4365 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4366
4367 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
4368 SCIP_CALL( findBestUbSafely(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
4369 }
4370 else
4371 {
4372 assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
4373
4374 /* user wants to use upper bound */
4375 *bestubtype = boundsfortrans[v];
4376 if( *bestubtype == -1 )
4377 *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
4378 else if( *bestubtype == -2 )
4379 *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
4380 else
4381 {
4382 SCIP_VAR** vubvars;
4383 SCIP_Real* vubcoefs;
4384 SCIP_Real* vubconsts;
4385 int k;
4386
4387 assert(!ignoresol);
4388
4389 /* use the given variable upper bound */
4390 vubvars = SCIPvarGetVubVars(var);
4391 vubcoefs = SCIPvarGetVubCoefs(var);
4392 vubconsts = SCIPvarGetVubConstants(var);
4393 k = boundsfortrans[v];
4394 assert(k >= 0 && k < SCIPvarGetNVubs(var));
4395 assert(vubvars != NULL);
4396 assert(vubcoefs != NULL);
4397 assert(vubconsts != NULL);
4398
4399 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4400 *bestub = vubcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vubvars[k]) : SCIPgetSolVal(scip, sol, vubvars[k])) + vubconsts[k];
4401 }
4402
4403 assert(!SCIPisInfinity(scip, *bestub));
4404 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4405
4406 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
4407 SCIP_CALL( findBestLbSafely(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
4408 }
4409 }
4410 else
4411 {
4412 SCIP_Real varsol;
4413
4414 /* bound selection should be done automatically */
4415
4416 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
4417 SCIP_CALL( findBestLbSafely(scip, var, sol, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
4418
4419 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
4420 SCIP_CALL( findBestUbSafely(scip, var, sol, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
4421
4422 /* check, if variable is free variable */
4423 if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
4424 {
4425 /* we found a free variable in the row with non-zero coefficient
4426 * -> MIR row can't be transformed in standard form
4427 */
4428 *freevariable = TRUE;
4429 return SCIP_OKAY;
4430 }
4431
4432 if( !ignoresol )
4433 {
4434 /* select transformation bound */
4435 varsol = (sol == NULL ? SCIPvarGetLPSol(var) : SCIPgetSolVal(scip, sol, var));
4436
4437 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
4438 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4439 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
4440 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4441 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
4442 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4443 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
4444 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4445 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
4446 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4447 else if( *bestubtype == -1 ) /* prefer global standard bounds */
4448 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4449 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
4450 {
4451 if( *bestlb - simplelb > simpleub - *bestub )
4452 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4453 else
4454 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4455 }
4456 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
4457 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4458 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
4459 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4460 else /* no decision yet? just use lower bound */
4461 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4462 }
4463 else
4464 {
4465 SCIP_Real glbub = SCIPvarGetUbGlobal(var);
4466 SCIP_Real glblb = SCIPvarGetLbGlobal(var);
4467 SCIP_Real distlb = REALABS(glblb - *bestlb);
4468 SCIP_Real distub = REALABS(glbub - *bestub);
4469
4470 assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
4471
4472 if( SCIPisInfinity(scip, - *bestlb) )
4473 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4474 else if( !SCIPisNegative(scip, *bestlb) )
4475 {
4476 if( SCIPisInfinity(scip, *bestub) )
4477 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4478 else if( SCIPisZero(scip, glblb) )
4479 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4480 else if( SCIPisLE(scip, distlb, distub) )
4481 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4482 else
4483 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4484 }
4485 else
4486 {
4487 assert(!SCIPisInfinity(scip, - *bestlb));
4488 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4489 }
4490 }
4491 }
4492
4493 return SCIP_OKAY; /*lint !e438*/
4494}
4495
4496/** finds the best lower bound of the variable to use for MIR transformation */
4497static
4499 SCIP* scip, /**< SCIP data structure */
4500 SCIP_VAR* var, /**< problem variable */
4501 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4502 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4503 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4504 SCIP_Real* bestlb, /**< pointer to store best bound value */
4505 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4506 )
4507{
4508 assert(bestlb != NULL);
4509 assert(bestlbtype != NULL);
4510 assert(usevbds >= 0 && usevbds <= 2);
4511
4512 *bestlb = SCIPvarGetLbGlobal(var);
4513 *bestlbtype = -1;
4514
4515 if( allowlocal )
4516 {
4517 SCIP_Real loclb;
4518
4519 loclb = SCIPvarGetLbLocal(var);
4520 if( SCIPisGT(scip, loclb, *bestlb) )
4521 {
4522 *bestlb = loclb;
4523 *bestlbtype = -2;
4524 }
4525 }
4526
4527 if( usevbds > 0 )
4528 {
4529 SCIP_Real bestvlb;
4530 int bestvlbidx;
4531
4532 SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
4533 if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
4534 {
4535 SCIP_VAR** vlbvars;
4536 SCIP_VAR* vlbvar;
4537
4538 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4539 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
4540 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
4541 */
4542 vlbvars = SCIPvarGetVlbVars(var);
4543 assert(vlbvars != NULL);
4544 vlbvar = vlbvars[bestvlbidx];
4545 assert(vlbvar != NULL);
4546 if( ( usevbds == 2 || ( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY
4547 && !SCIPvarIsImpliedIntegral(vlbvar) ) ) )
4548 {
4549 assert(SCIPvarGetProbindex(vlbvar) < SCIPvarGetProbindex(var));
4550 *bestlb = bestvlb;
4551 *bestlbtype = bestvlbidx;
4552 }
4553 }
4554 }
4555
4556 return SCIP_OKAY;
4557}
4558
4559/** finds the best upper bound of the variable to use for MIR transformation */
4560static
4562 SCIP* scip, /**< SCIP data structure */
4563 SCIP_VAR* var, /**< problem variable */
4564 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4565 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4566 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4567 SCIP_Real* bestub, /**< pointer to store best bound value */
4568 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4569 )
4570{
4571 assert(bestub != NULL);
4572 assert(bestubtype != NULL);
4573 assert(usevbds >= 0 && usevbds <= 2);
4574
4575 *bestub = SCIPvarGetUbGlobal(var);
4576 *bestubtype = -1;
4577
4578 if( allowlocal )
4579 {
4580 SCIP_Real locub;
4581
4582 locub = SCIPvarGetUbLocal(var);
4583 if( SCIPisLT(scip, locub, *bestub) )
4584 {
4585 *bestub = locub;
4586 *bestubtype = -2;
4587 }
4588 }
4589
4590 if( usevbds > 0 )
4591 {
4592 SCIP_Real bestvub;
4593 int bestvubidx;
4594
4595 SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
4596 if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
4597 {
4598 SCIP_VAR** vubvars;
4599 SCIP_VAR* vubvar;
4600
4601 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
4602 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
4603 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
4604 */
4605 vubvars = SCIPvarGetVubVars(var);
4606 assert(vubvars != NULL);
4607 vubvar = vubvars[bestvubidx];
4608 assert(vubvar != NULL);
4609 if( ( usevbds == 2 || ( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY
4610 && !SCIPvarIsImpliedIntegral(vubvar) ) ) )
4611 {
4612 assert( SCIPvarGetProbindex(vubvar) < SCIPvarGetProbindex(var) );
4613 *bestub = bestvub;
4614 *bestubtype = bestvubidx;
4615 }
4616 }
4617 }
4618
4619 return SCIP_OKAY;
4620}
4621
4622
4623/** finds the best lower bound of the variable to use for MIR transformation.
4624 * Differs from findBestLB() in that it allows more variable bound substitutions based on the variable sections. */
4625static
4627 SCIP* scip, /**< SCIP data structure */
4628 SCIP_VAR* var, /**< problem variable */
4629 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4630 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
4631 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4632 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4633 SCIP_Real* bestlb, /**< pointer to store best bound value */
4634 SCIP_Real* simplebound, /**< pointer to store simple bound value */
4635 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4636 )
4637{
4638 assert(bestlb != NULL);
4639 assert(bestlbtype != NULL);
4640 assert(usevbds >= 0 && usevbds <= 2);
4641
4642 *bestlb = SCIPvarGetLbGlobal(var);
4643 *bestlbtype = -1;
4644
4645 if( allowlocal )
4646 {
4647 SCIP_Real loclb;
4648
4649 loclb = SCIPvarGetLbLocal(var);
4650 if( SCIPisGT(scip, loclb, *bestlb) )
4651 {
4652 *bestlb = loclb;
4653 *bestlbtype = -2;
4654 }
4655 }
4656
4657 *simplebound = *bestlb;
4658
4659 if( usevbds > 0 )
4660 {
4661 int nvlbs = SCIPvarGetNVlbs(var);
4662
4663 if( nvlbs > 0 )
4664 {
4665 SCIP_Real bestvlb = SCIP_REAL_MIN;
4666 int bestvlbtype = -1;
4667 int boundedsection = varSection(data, SCIPvarGetProbindex(var));
4668
4669 SCIP_VAR** vlbvars;
4670 SCIP_Real* vlbcoefs;
4671 SCIP_Real* vlbconsts;
4672 int i;
4673
4674 vlbvars = SCIPvarGetVlbVars(var);
4675 vlbcoefs = SCIPvarGetVlbCoefs(var);
4676 vlbconsts = SCIPvarGetVlbConstants(var);
4677
4678 /* search best VLB */
4679 for( i = 0; i < nvlbs; i++ )
4680 {
4681 /* For now, we only allow variable bounds from sections that are strictly greater to prevent cyclic usage.*/
4682 /** @todo: We don't use the caching mechanism of SCIPvarGetClosestVLB() because the cached variable bound
4683 * may be illegal. Building a local cache here may be worth it. */
4684 if( SCIPvarIsActive(vlbvars[i]) && boundedsection < varSection(data, SCIPvarGetProbindex(vlbvars[i])) &&
4685 (usevbds == 2 || SCIPvarIsBinary(vlbvars[i])) )
4686 {
4687 SCIP_Real vlbsol;
4688 SCIP_Real vlbbnd;
4689
4690 vlbsol = SCIPgetSolVal(scip, sol, vlbvars[i]);
4691 vlbbnd = vlbcoefs[i] * vlbsol + vlbconsts[i];
4692
4693 if( vlbbnd > bestvlb )
4694 {
4695 bestvlb = vlbbnd;
4696 bestvlbtype = i;
4697 }
4698 }
4699 }
4700
4701 if( bestvlbtype >= 0 && SCIPisGE(scip, bestvlb, *bestlb) )
4702 {
4703 *bestlb = bestvlb;
4704 *bestlbtype = bestvlbtype;
4705 }
4706 }
4707 }
4708
4709 return SCIP_OKAY;
4710}
4711
4712/** finds the best upper bound of the variable to use for MIR transformation.
4713 * Differs from findBestUB() in that it allows more variable bound substitutions based on the variable sections. */
4714static
4716 SCIP* scip, /**< SCIP data structure */
4717 SCIP_VAR* var, /**< problem variable */
4718 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4719 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
4720 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4721 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4722 SCIP_Real* bestub, /**< pointer to store best bound value */
4723 SCIP_Real* simplebound, /**< pointer to store simple bound */
4724 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
4725 )
4726{
4727 assert(bestub != NULL);
4728 assert(bestubtype != NULL);
4729 assert(usevbds >= 0 && usevbds <= 2);
4730
4731 *bestub = SCIPvarGetUbGlobal(var);
4732 *bestubtype = -1;
4733
4734 if( allowlocal )
4735 {
4736 SCIP_Real locub;
4737
4738 locub = SCIPvarGetUbLocal(var);
4739 if( SCIPisLT(scip, locub, *bestub) )
4740 {
4741 *bestub = locub;
4742 *bestubtype = -2;
4743 }
4744 }
4745
4746 *simplebound = *bestub;
4747
4748 if( usevbds > 0 )
4749 {
4750 int nvubs = SCIPvarGetNVubs(var);
4751
4752 if( nvubs > 0 )
4753 {
4754 SCIP_Real bestvub = SCIP_REAL_MAX;
4755 int bestvubtype = -1;
4756 int boundedsection = varSection(data, SCIPvarGetProbindex(var));
4757
4758 SCIP_VAR** vubvars;
4759 SCIP_Real* vubcoefs;
4760 SCIP_Real* vubconsts;
4761 int i;
4762
4763 vubvars = SCIPvarGetVubVars(var);
4764 vubcoefs = SCIPvarGetVubCoefs(var);
4765 vubconsts = SCIPvarGetVubConstants(var);
4766
4767 /* search best VUB */
4768 for( i = 0; i < nvubs; i++ )
4769 {
4770 /* For now, we only allow variable bounds from sections that are strictly greater to prevent cyclic usage.*/
4771 /** @todo: We don't use the caching mechanism of SCIPvarGetClosestVLB() because the cached variable bound
4772 * may be illegal. Building a local cache here may be worth it. */
4773 if( SCIPvarIsActive(vubvars[i]) && boundedsection < varSection(data, SCIPvarGetProbindex(vubvars[i])) &&
4774 (usevbds == 2 || SCIPvarIsBinary(vubvars[i])) )
4775 {
4776 SCIP_Real vubsol;
4777 SCIP_Real vubbnd;
4778
4779 vubsol = SCIPgetSolVal(scip, sol, vubvars[i]);
4780 vubbnd = vubcoefs[i] * vubsol + vubconsts[i];
4781
4782 if( vubbnd < bestvub )
4783 {
4784 bestvub = vubbnd;
4785 bestvubtype = i;
4786 }
4787 }
4788 }
4789
4790 if( bestvubtype >= 0 && SCIPisLE(scip, bestvub, *bestub) )
4791 {
4792 *bestub = bestvub;
4793 *bestubtype = bestvubtype;
4794 }
4795 }
4796 }
4797
4798 return SCIP_OKAY;
4799}
4800
4801/** determine the best bounds with respect to the given solution for complementing the given variable */
4802static
4804 SCIP* scip, /**< SCIP data structure */
4805 SCIP_VAR* var, /**< variable to determine best bound for */
4806 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4807 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
4808 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
4809 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
4810 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4811 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
4812 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
4813 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
4814 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
4815 * NULL for using closest bound for all variables */
4816 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
4817 * NULL for using closest bound for all variables */
4818 SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
4819 SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
4820 int* bestlbtype, /**< pointer to store type of best lower bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
4821 int* bestubtype, /**< pointer to store type of best upper bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
4822 SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
4823 SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
4824 )
4825{
4826 SCIP_Real simplelb;
4827 SCIP_Real simpleub;
4828 int v;
4829
4830 assert(usevbds >= 0 && usevbds <= 2);
4831
4832 v = SCIPvarGetProbindex(var);
4833
4834 /* check if the user specified a bound to be used */
4835 if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
4836 {
4837 assert(!SCIPvarIsIntegral(var) || boundsfortrans[v] == -2 || boundsfortrans[v] == -1);
4838 assert(boundtypesfortrans != NULL);
4839
4840 /* user has explicitly specified a bound to be used */
4841 if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
4842 {
4843 /* user wants to use lower bound */
4844 *bestlbtype = boundsfortrans[v];
4845 if( *bestlbtype == -1 )
4846 *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
4847 else if( *bestlbtype == -2 )
4848 *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
4849 else
4850 {
4851 SCIP_Real vlbsol;
4852 SCIP_VAR** vlbvars;
4853 SCIP_Real* vlbcoefs;
4854 SCIP_Real* vlbconsts;
4855 int k;
4856
4857 assert(!ignoresol);
4858
4859 /* use the given variable lower bound */
4860 vlbvars = SCIPvarGetVlbVars(var);
4861 vlbcoefs = SCIPvarGetVlbCoefs(var);
4862 vlbconsts = SCIPvarGetVlbConstants(var);
4863 k = boundsfortrans[v];
4864 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
4865 assert(vlbvars != NULL);
4866 assert(vlbcoefs != NULL);
4867 assert(vlbconsts != NULL);
4868
4869 vlbsol = SCIPgetSolVal(scip, sol, vlbvars[k]);
4870
4871 *bestlb = vlbcoefs[k] * vlbsol + vlbconsts[k];
4872 }
4873
4874 assert(!SCIPisInfinity(scip, - *bestlb));
4875 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4876
4877 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
4878 SCIP_CALL( findMIRBestUb(scip, var, sol, data, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
4879 }
4880 else
4881 {
4882 assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
4883
4884 /* user wants to use upper bound */
4885 *bestubtype = boundsfortrans[v];
4886 if( *bestubtype == -1 )
4887 *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
4888 else if( *bestubtype == -2 )
4889 *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
4890 else
4891 {
4892 SCIP_Real vubsol;
4893 SCIP_VAR** vubvars;
4894 SCIP_Real* vubcoefs;
4895 SCIP_Real* vubconsts;
4896 int k;
4897
4898 assert(!ignoresol);
4899
4900 /* use the given variable upper bound */
4901 vubvars = SCIPvarGetVubVars(var);
4902 vubcoefs = SCIPvarGetVubCoefs(var);
4903 vubconsts = SCIPvarGetVubConstants(var);
4904 k = boundsfortrans[v];
4905 assert(k >= 0 && k < SCIPvarGetNVubs(var));
4906 assert(vubvars != NULL);
4907 assert(vubcoefs != NULL);
4908 assert(vubconsts != NULL);
4909
4910 vubsol = SCIPgetSolVal(scip, sol, vubvars[k]);
4911 *bestub = vubcoefs[k] * vubsol + vubconsts[k];
4912 }
4913
4914 assert(!SCIPisInfinity(scip, *bestub));
4915 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4916
4917 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
4918 SCIP_CALL( findMIRBestLb(scip, var, sol, data, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
4919 }
4920 }
4921 else
4922 {
4923 SCIP_Real varsol;
4924
4925 /* bound selection should be done automatically */
4926
4927 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
4928 SCIP_CALL( findMIRBestLb(scip, var, sol, data, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
4929
4930 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
4931 SCIP_CALL( findMIRBestUb(scip, var, sol, data, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
4932
4933 /* check, if variable is free variable */
4934 if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
4935 {
4936 /* we found a free variable in the row with non-zero coefficient
4937 * -> MIR row can't be transformed in standard form
4938 */
4939 *freevariable = TRUE;
4940 return SCIP_OKAY;
4941 }
4942
4943 if( !ignoresol )
4944 {
4945 /* select transformation bound */
4946 varsol = SCIPgetSolVal(scip, sol, var);
4947
4948 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
4949 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4950 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
4951 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4952 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
4953 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4954 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
4955 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4956 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
4957 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4958 else if( *bestubtype == -1 ) /* prefer global standard bounds */
4959 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4960 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
4961 {
4962 if( *bestlb - simplelb > simpleub - *bestub )
4963 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4964 else
4965 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4966 }
4967 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
4968 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4969 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
4970 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4971 else /* no decision yet? just use lower bound */
4972 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4973 }
4974 else
4975 {
4976 SCIP_Real glbub = SCIPvarGetUbGlobal(var);
4977 SCIP_Real glblb = SCIPvarGetLbGlobal(var);
4978 SCIP_Real distlb = REALABS(glblb - *bestlb);
4979 SCIP_Real distub = REALABS(glbub - *bestub);
4980
4981 assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
4982
4983 if( SCIPisInfinity(scip, - *bestlb) )
4984 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4985 else if( !SCIPisNegative(scip, *bestlb) )
4986 {
4987 if( SCIPisInfinity(scip, *bestub) )
4988 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4989 else if( SCIPisZero(scip, glblb) )
4990 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4991 else if( SCIPisLE(scip, distlb, distub) )
4992 *selectedbound = SCIP_BOUNDTYPE_LOWER;
4993 else
4994 *selectedbound = SCIP_BOUNDTYPE_UPPER;
4995 }
4996 else
4997 {
4998 assert(!SCIPisInfinity(scip, - *bestlb));
4999 *selectedbound = SCIP_BOUNDTYPE_LOWER;
5000 }
5001 }
5002 }
5003
5004 return SCIP_OKAY; /*lint !e438*/
5005}
5006
5007/** Performs bound substitution for a MIR cut */
5008static
5010 SCIP* scip, /**< SCIP datastructure */
5011 MIR_DATA* data, /**< the MIR data structure for this cut */
5012 int varsign, /**< stores the sign of the transformed variable in summation */
5013 int boundtype, /**< stores the bound used for transformed variable:
5014 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5015 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5016 int probindex, /**< problem index of variable to perform the substitution step for */
5017 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5018 )
5019{
5020 SCIP_Real QUAD(coef);
5021 SCIP_Real QUAD(tmp);
5022
5023 assert(!SCIPisInfinity(scip, -varsign * boundval));
5024
5025 QUAD_ARRAY_LOAD(coef, data->cutcoefs, probindex);
5026
5027 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
5028 if( boundtype < 0 )
5029 {
5030 SCIPquadprecProdQD(tmp, coef, boundval);
5031 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, -tmp);
5032 *localbdsused = *localbdsused || ( boundtype == -2 );
5033 }
5034 else
5035 {
5036 SCIP_VAR** vbdvars;
5037 SCIP_Real* vbdcoefs;
5038 SCIP_Real* vbdconsts;
5039 SCIP_Real QUAD(zcoef);
5040 int zidx;
5041 SCIP_VAR* var = SCIPgetVars(scip)[probindex];
5042
5043 if( varsign == +1 )
5044 {
5045 vbdvars = SCIPvarGetVlbVars(var);
5046 vbdcoefs = SCIPvarGetVlbCoefs(var);
5047 vbdconsts = SCIPvarGetVlbConstants(var);
5048 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
5049 }
5050 else
5051 {
5052 vbdvars = SCIPvarGetVubVars(var);
5053 vbdcoefs = SCIPvarGetVubCoefs(var);
5054 vbdconsts = SCIPvarGetVubConstants(var);
5055 assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
5056 }
5057
5058 assert(vbdvars != NULL);
5059 assert(vbdcoefs != NULL);
5060 assert(vbdconsts != NULL);
5061 assert(SCIPvarIsActive(vbdvars[boundtype]));
5062
5063 zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
5064
5065 SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
5066 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, -tmp);
5067
5068 /* check if integral variable already exists in the row */
5069 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
5070
5071 /* If it is new, add it to the indices */
5072 if( QUAD_HI(zcoef) == 0.0 )
5073 {
5074 int section = varSection(data, zidx);
5075 assert(section > varSection(data, probindex));
5076
5077 data->secindices[section][data->secnnz[section]] = zidx;
5078 ++data->secnnz[section];
5079 ++data->totalnnz;
5080 }
5081
5082 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
5083 SCIPquadprecSumQQ(zcoef, zcoef, tmp);
5084
5085 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
5086 assert(QUAD_HI(zcoef) != 0.0);
5087
5088 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
5089 }
5090}
5091
5092/** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index
5093 *
5094 * @note this method is safe for usage in exact solving mode
5095 *
5096 * @todo make behavior identical to the unsafe MIR cut computation
5097 */
5098static
5100 SCIP* scip, /**< SCIP datastructure */
5101 SCIP_Real* cutcoefs, /**< array of cut coefficients */
5102 SCIP_Real* cutrhs, /**< pointer to right hand side of the cut */
5103 int varsign, /**< stores the sign of the transformed variable in summation */
5104 int boundtype, /**< stores the bound used for transformed variable:
5105 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5106 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5107 int probindex, /**< problem index of variable to perform the substitution step for */
5108 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5109 )
5110{
5111 SCIP_Real coef;
5112 SCIP_ROUNDMODE previousroundmode;
5113
5114 assert(!SCIPisInfinity(scip, -varsign * boundval));
5115 assert(SCIPisExact(scip));
5116
5117 previousroundmode = SCIPintervalGetRoundingMode();
5119
5120 coef = cutcoefs[probindex];
5121
5122 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
5123 if( boundtype < 0 )
5124 {
5125 *cutrhs += coef * (-boundval);
5126 *localbdsused = *localbdsused || (boundtype == -2);
5127 }
5128 else
5129 {
5130 /* we don't support vlbs in exact mode yet */
5131 assert(!SCIPisExact(scip));
5132 SCIPerrorMessage("variable lower bounds not implemented in exact solving mode yet \n");
5133 SCIPABORT();
5134 }
5135
5136 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
5137}
5138
5139/** performs the bound substitution step with the simple bound for the variable with the given problem index
5140 *
5141 * @note this method is safe for usage in exact solving mode
5142 *
5143 * @todo make behavior identical to the unsafe MIR cut computation
5144 */
5145static
5147 SCIP* scip, /**< SCIP datastructure */
5148 SCIP_Real* cutcoefs, /**< array of cut coefficients */
5149 SCIP_Real* cutrhs, /**< pointer to right hand side of the cut */
5150 int boundtype, /**< stores the bound used for transformed variable:
5151 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5152 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5153 int probindex, /**< problem index of variable to perform the substitution step for */
5154 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5155 )
5156{
5157 SCIP_Real coef;
5158 SCIP_ROUNDMODE previousroundmode;
5159
5160 assert(!SCIPisInfinity(scip, ABS(boundval)));
5161 assert(SCIPisExact(scip));
5162
5163 previousroundmode = SCIPintervalGetRoundingMode();
5165
5166 coef = cutcoefs[probindex];
5167
5168 /* must be a standard bound */
5169 assert( boundtype < 0 );
5170
5171 *cutrhs += coef * (-boundval);
5172
5173 *localbdsused = *localbdsused || (boundtype == -2);
5174
5175 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
5176}
5177
5178/** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index */
5179static
5181 SCIP* scip, /**< SCIP datastructure */
5182 int* cutinds, /**< index array of nonzeros in the cut */
5183 SCIP_Real* cutcoefs, /**< array of cut coefficients */
5184 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
5185 int* nnz, /**< pointer to number of nonzeros of the cut */
5186 int varsign, /**< stores the sign of the transformed variable in summation */
5187 int boundtype, /**< stores the bound used for transformed variable:
5188 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5189 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5190 int probindex, /**< problem index of variable to perform the substitution step for */
5191 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5192 )
5193{
5194 SCIP_Real QUAD(coef);
5195 SCIP_Real QUAD(tmp);
5196
5197 assert(!SCIPisInfinity(scip, -varsign * boundval));
5198 assert(!SCIPisExact(scip));
5199
5200 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
5201
5202 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
5203 if( boundtype < 0 )
5204 {
5205 SCIPquadprecProdQD(tmp, coef, boundval);
5206 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
5207 *localbdsused = *localbdsused || (boundtype == -2);
5208 }
5209 else
5210 {
5211 SCIP_VAR** vbdvars;
5212 SCIP_Real* vbdcoefs;
5213 SCIP_Real* vbdconsts;
5214 SCIP_Real QUAD(zcoef);
5215 int zidx;
5216 SCIP_VAR* var = SCIPgetVars(scip)[probindex];
5217
5218 if( varsign == +1 )
5219 {
5220 vbdvars = SCIPvarGetVlbVars(var);
5221 vbdcoefs = SCIPvarGetVlbCoefs(var);
5222 vbdconsts = SCIPvarGetVlbConstants(var);
5223 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
5224 }
5225 else
5226 {
5227 vbdvars = SCIPvarGetVubVars(var);
5228 vbdcoefs = SCIPvarGetVubCoefs(var);
5229 vbdconsts = SCIPvarGetVubConstants(var);
5230 assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
5231 }
5232
5233 assert(vbdvars != NULL);
5234 assert(vbdcoefs != NULL);
5235 assert(vbdconsts != NULL);
5236 assert(SCIPvarIsActive(vbdvars[boundtype]));
5237
5238 zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
5239
5240 SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
5241 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
5242
5243 /* check if integral variable already exists in the row */
5244 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
5245
5246 if( QUAD_HI(zcoef) == 0.0 )
5247 cutinds[(*nnz)++] = zidx;
5248
5249 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
5250 SCIPquadprecSumQQ(zcoef, zcoef, tmp);
5251
5252 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
5253 assert(QUAD_HI(zcoef) != 0.0);
5254
5255 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
5256 }
5257}
5258
5259/** performs the bound substitution step with the simple bound for the variable with the given problem index */
5260static
5262 SCIP* scip, /**< SCIP datastructure */
5263 SCIP_Real* cutcoefs, /**< array of cut coefficients */
5264 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
5265 int boundtype, /**< stores the bound used for transformed variable:
5266 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5267 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
5268 int probindex, /**< problem index of variable to perform the substitution step for */
5269 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
5270 )
5271{
5272 SCIP_Real QUAD(coef);
5273 SCIP_Real QUAD(tmp);
5274
5275 assert(!SCIPisInfinity(scip, ABS(boundval)));
5276 assert(!SCIPisExact(scip));
5277
5278 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
5279
5280 /* must be a standard bound */
5281 assert( boundtype < 0 );
5282
5283 SCIPquadprecProdQD(tmp, coef, boundval);
5284 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
5285 *localbdsused = *localbdsused || (boundtype == -2);
5286}
5287
5288/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
5289 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
5290 *
5291 * Transform variables (lb or ub):
5292 * \f[
5293 * \begin{array}{llll}
5294 * 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},\\
5295 * 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},
5296 * \end{array}
5297 * \f]
5298 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
5299 *
5300 * Transform variables (vlb or vub):
5301 * \f[
5302 * \begin{array}{llll}
5303 * 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.} \\
5304 * 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.}
5305 * \end{array}
5306 * \f]
5307 * 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:
5308 * \f[
5309 * \begin{array}{ll}
5310 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
5311 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
5312 * \end{array}
5313 * \f]
5314 *
5315 * @note this method is safe for usage in exact solving mode
5316 *
5317 * @todo make behavior identical to the unsafe MIR cut computation
5318 */
5319static
5321 SCIP* scip, /**< SCIP data structure */
5322 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
5323 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5324 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
5325 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5326 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
5327 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
5328 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
5329 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
5330 * NULL for using closest bound for all variables */
5331 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
5332 * NULL for using closest bound for all variables */
5333 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
5334 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
5335 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
5336 int* nnz, /**< number of non-zeros in cut */
5337 int* varsign, /**< stores the sign of the transformed variable in summation */
5338 int* boundtype, /**< stores the bound used for transformed variable:
5339 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5340 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
5341 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
5342 )
5343{ /*lint --e{644}*/
5344 SCIP_Real* bestlbs;
5345 SCIP_Real* bestubs;
5346 int* bestlbtypes;
5347 int* bestubtypes;
5348 SCIP_BOUNDTYPE* selectedbounds;
5349 int i;
5350 int aggrrowintstart;
5351 int nvars;
5352 int firstcontvar;
5353 SCIP_VAR** vars;
5354 SCIP_MIRINFO* mirinfo = NULL;
5355
5356 SCIP_ROUNDMODE previousroundmode;
5357
5358 assert(varsign != NULL);
5359 assert(boundtype != NULL);
5360 assert(freevariable != NULL);
5361 assert(localbdsused != NULL);
5362 assert(SCIPisExact(scip));
5363
5364 if( SCIPisCertified(scip) )
5366 previousroundmode = SCIPintervalGetRoundingMode();
5368
5369 *freevariable = FALSE;
5370 *localbdsused = FALSE;
5371
5372 /* allocate temporary memory to store best bounds and bound types */
5373 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*(*nnz)) );
5374 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*(*nnz)) );
5375 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*(*nnz)) );
5376 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*(*nnz)) );
5377 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*(*nnz)) );
5378
5379 /* start with continuous variables, because using variable bounds can affect the untransformed integral
5380 * variables, and these changes have to be incorporated in the transformation of the integral variables
5381 * (continuous variables have largest problem indices!)
5382 */
5383 SCIPsortDownInt(cutinds, *nnz);
5384
5385 vars = SCIPgetVars(scip);
5386 nvars = SCIPgetNVars(scip);
5387 firstcontvar = nvars - SCIPgetNContVars(scip);
5388
5389 /* determine the best bounds for the continuous variables */
5390 for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
5391 {
5392 SCIP_CALL( determineBestBoundsSafely(scip, vars[cutinds[i]], sol, boundswitch, usevbds ? 2 : 0, allowlocal, fixintegralrhs,
5393 ignoresol, boundsfortrans, boundtypesfortrans,
5394 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
5395
5396 if( *freevariable )
5397 goto TERMINATE;
5398 }
5399
5400 /* remember start of integer variables in the aggrrow */
5401 aggrrowintstart = i;
5402
5403 /* perform bound substitution for continuous variables */
5404 for( i = 0; i < aggrrowintstart; ++i )
5405 {
5406 int v = cutinds[i];
5407
5408 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5409 {
5410 assert(!SCIPisInfinity(scip, -bestlbs[i]));
5411
5412 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
5413 boundtype[i] = bestlbtypes[i];
5414 varsign[i] = +1;
5415
5416 performBoundSubstitutionSafely(scip, cutcoefs, cutrhs, varsign[i], boundtype[i], bestlbs[i], v, localbdsused);
5417 }
5418 else
5419 {
5420 assert(!SCIPisInfinity(scip, bestubs[i]));
5421
5422 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
5423 boundtype[i] = bestubtypes[i];
5424 varsign[i] = -1;
5425
5426 performBoundSubstitutionSafely(scip, cutcoefs, cutrhs, varsign[i], boundtype[i], bestubs[i], v, localbdsused);
5427 }
5428
5429 if( SCIPisCertified(scip) )
5430 {
5431 assert(mirinfo != NULL);
5432 if( boundtype[i] == -2 )
5433 {
5434 mirinfo->localbdused[v] = TRUE;
5435 mirinfo->nlocalvars++;
5436 }
5437 mirinfo->upperused[v] = (varsign[i] == -1);
5438 }
5439 }
5440
5441 /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
5442 * and determine the bound to use for the integer variables that are left
5443 */
5444 while( i < *nnz )
5445 {
5446 int v = cutinds[i];
5447 assert(cutinds[i] < firstcontvar);
5448
5449 /* determine the best bounds for the integral variable, usevbd can be set to 0 here as vbds are only used for continuous variables */
5450 SCIP_CALL( determineBestBoundsSafely(scip, vars[v], sol, boundswitch, 0, allowlocal, fixintegralrhs,
5451 ignoresol, boundsfortrans, boundtypesfortrans,
5452 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
5453
5454 /* increase i */
5455 ++i;
5456
5457 if( *freevariable )
5458 goto TERMINATE;
5459 }
5460
5461 /* now perform the bound substitution on the remaining integral variables which only uses standard bounds */
5462 for( i = aggrrowintstart; i < *nnz; ++i )
5463 {
5464 int v = cutinds[i];
5465
5466 /* perform bound substitution */
5467 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5468 {
5469 assert(!SCIPisInfinity(scip, - bestlbs[i]));
5470 assert(bestlbtypes[i] < 0);
5471
5472 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
5473 boundtype[i] = bestlbtypes[i];
5474 varsign[i] = +1;
5475
5476 performBoundSubstitutionSimpleSafely(scip, cutcoefs, cutrhs, boundtype[i], bestlbs[i], v, localbdsused);
5477 }
5478 else
5479 {
5480 assert(!SCIPisInfinity(scip, bestubs[i]));
5481 assert(bestubtypes[i] < 0);
5482
5483 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
5484 boundtype[i] = bestubtypes[i];
5485 varsign[i] = -1;
5486
5487 performBoundSubstitutionSimpleSafely(scip, cutcoefs, cutrhs, boundtype[i], bestubs[i], v, localbdsused);
5488 }
5489
5490 if( SCIPisCertified(scip) )
5491 {
5492 assert(mirinfo != NULL);
5493 if( boundtype[i] == -2 )
5494 {
5495 mirinfo->localbdused[v] = TRUE;
5496 mirinfo->nlocalvars++;
5497 }
5498 mirinfo->upperused[v] = (varsign[i] == -1);
5499 }
5500 }
5501
5502 TERMINATE:
5503 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
5504
5505 /*free temporary memory */
5506 SCIPfreeBufferArray(scip, &selectedbounds);
5507 SCIPfreeBufferArray(scip, &bestubtypes);
5508 SCIPfreeBufferArray(scip, &bestlbtypes);
5509 SCIPfreeBufferArray(scip, &bestubs);
5510 SCIPfreeBufferArray(scip, &bestlbs);
5511
5512 return SCIP_OKAY;
5513}
5514
5515/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
5516 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
5517 *
5518 * Transform variables (lb or ub):
5519 * \f[
5520 * \begin{array}{llll}
5521 * 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},\\
5522 * 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},
5523 * \end{array}
5524 * \f]
5525 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
5526 *
5527 * Transform variables (vlb or vub):
5528 * \f[
5529 * \begin{array}{llll}
5530 * 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.} \\
5531 * 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.}
5532 * \end{array}
5533 * \f]
5534 * 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:
5535 * \f[
5536 * \begin{array}{ll}
5537 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
5538 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
5539 * \end{array}
5540 * \f]
5541 */
5542static
5544 SCIP* scip, /**< SCIP datastructure */
5545 MIR_DATA* data, /**< the MIR data structure for this cut */
5546 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
5547 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5548 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5549 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
5550 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
5551 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
5552 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
5553 * NULL for using closest bound for all variables */
5554 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
5555 * NULL for using closest bound for all variables */
5556 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
5557 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
5558 int* varsign, /**< stores the sign of the transformed variable in summation */
5559 int* boundtype, /**< stores the bound used for transformed variable:
5560 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
5561 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
5562 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
5563 )
5564{
5565 SCIP_Real* bestlbs;
5566 SCIP_Real* bestubs;
5567 int* bestlbtypes;
5568 int* bestubtypes;
5569 SCIP_BOUNDTYPE* selectedbounds;
5570 SCIP_Real QUAD(coef);
5571 int totalnnz;
5572 int s;
5573 int i;
5574
5575 assert(data != NULL);
5576 assert(varsign != NULL);
5577 assert(boundtype != NULL);
5578 assert(freevariable != NULL);
5579 assert(localbdsused != NULL);
5580
5581 totalnnz = data->totalnnz;
5582
5583 *freevariable = FALSE;
5584 *localbdsused = FALSE;
5585
5586 int allocsize = MIN(NSECTIONS * totalnnz, data->nvars);
5587 /* allocate temporary memory to store best bounds and bound types */
5588 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, allocsize) );
5589 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, allocsize) );
5590 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, allocsize) );
5591 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, allocsize) );
5592 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, allocsize) );
5593
5594 /* transform the cut, one variable section at a time */
5595 for( s = 0; s < NSECTIONS; ++s )
5596 {
5597 int* indices = data->secindices[s];
5598 int cutindsstart = data->ncutinds;
5599 int usevbds = data->usevbds[s];
5600
5601 i = 0;
5602 while( i < data->secnnz[s] )
5603 {
5604 int cutindex;
5605 int v = indices[i];
5606
5607 /* due to variable bound usage, cancellation may have occurred */
5608 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
5609 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
5610 {
5611 QUAD_ASSIGN(coef, 0.0);
5612 QUAD_ARRAY_STORE(data->cutcoefs, v, coef);
5613 --data->secnnz[s];
5614 --data->totalnnz;
5615 indices[i] = indices[data->secnnz[s]];
5616 /* do not increase the index */
5617 continue;
5618 }
5619
5620 cutindex = data->ncutinds;
5621 assert(cutindex < allocsize);
5622 SCIP_CALL( determineBestBounds(scip, data->vars[v], sol, data, boundswitch, usevbds, allowlocal, fixintegralrhs,
5623 ignoresol, boundsfortrans, boundtypesfortrans,
5624 bestlbs + cutindex, bestubs + cutindex, bestlbtypes + cutindex, bestubtypes + cutindex,
5625 selectedbounds + cutindex, freevariable) );
5626
5627 data->cutinds[cutindex] = v;
5628 ++data->ncutinds;
5629
5630 ++i;
5631
5632 /* if there is a free variable, we terminate because we cannot derive a MIR cut */
5633 if( *freevariable )
5634 {
5635 int j;
5636 int k;
5637
5638 data->ncutinds = 0;
5639
5640 /* if we terminate early, we need to make sure all the zeros in the cut coefficient array are cancelled */
5641 for( j = 0; j < NSECTIONS; ++j )
5642 {
5643 int* indexlist = data->secindices[j];
5644 for( k = 0; k < data->secnnz[j]; ++k )
5645 {
5646 data->cutinds[data->ncutinds] = indexlist[k];
5647 ++data->ncutinds;
5648 }
5649 }
5650 goto TERMINATE;
5651 }
5652 }
5653
5654 /* perform bound substitution for added variables */
5655 for( i = cutindsstart; i < data->ncutinds; ++i )
5656 {
5657 SCIP_Real bestbnd;
5658 int v = data->cutinds[i];
5659
5660 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5661 {
5662 assert(!SCIPisInfinity(scip, -bestlbs[i]));
5663
5664 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
5665 boundtype[i] = bestlbtypes[i];
5666 varsign[i] = +1;
5667 bestbnd = bestlbs[i];
5668 }
5669 else
5670 {
5671 assert(!SCIPisInfinity(scip, bestubs[i]));
5672
5673 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
5674 boundtype[i] = bestubtypes[i];
5675 varsign[i] = -1;
5676 bestbnd = bestubs[i];
5677 }
5678 doMIRBoundSubstitution(scip, data, varsign[i], boundtype[i], bestbnd, v, localbdsused);
5679 }
5680 }
5681
5682 if( fixintegralrhs )
5683 {
5684 SCIP_Real f0;
5685
5686 /* check if rhs is fractional */
5687 f0 = EPSFRAC(QUAD_TO_DBL(data->cutrhs), SCIPsumepsilon(scip));
5688 if( f0 < minfrac || f0 > maxfrac )
5689 {
5690 SCIP_Real bestviolgain;
5691 SCIP_Real bestnewf0;
5692 int besti;
5693
5694 /* choose complementation of one variable differently such that f0 is in correct range */
5695 besti = -1;
5696 bestviolgain = -1e+100;
5697 bestnewf0 = 1.0;
5698 for( i = 0; i < data->ncutinds; i++ )
5699 {
5700 int v;
5701
5702 v = data->cutinds[i];
5703 assert(0 <= v && v < data->nvars);
5704
5705 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
5706 assert(!EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON));
5707
5708 if( boundtype[i] < 0
5709 && ((varsign[i] == +1 && !SCIPisInfinity(scip, bestubs[i]) && bestubtypes[i] < 0)
5710 || (varsign[i] == -1 && !SCIPisInfinity(scip, -bestlbs[i]) && bestlbtypes[i] < 0)) )
5711 {
5712 SCIP_Real fj;
5713 SCIP_Real newfj;
5714 SCIP_Real newrhs;
5715 SCIP_Real newf0;
5716 SCIP_Real solval;
5717 SCIP_Real viol;
5718 SCIP_Real newviol;
5719 SCIP_Real violgain;
5720
5721 /* currently: a'_j = varsign * a_j -> f'_j = a'_j - floor(a'_j)
5722 * after complementation: a''_j = -varsign * a_j -> f''_j = a''_j - floor(a''_j) = 1 - f'_j
5723 * rhs'' = rhs' + varsign * a_j * (lb_j - ub_j)
5724 * cut violation from f0 and fj: f'_0 - f'_j * x'_j
5725 * after complementation: f''_0 - f''_j * x''_j
5726 *
5727 * for continuous variables, we just set f'_j = f''_j = |a'_j|
5728 */
5729 newrhs = QUAD_TO_DBL(data->cutrhs) + varsign[i] * QUAD_TO_DBL(coef) * (bestlbs[i] - bestubs[i]);
5730 newf0 = EPSFRAC(newrhs, SCIPsumepsilon(scip));
5731
5732 if( newf0 < minfrac || newf0 > maxfrac )
5733 continue;
5734 if( v >= data->nvars - data->ncontvars )
5735 {
5736 fj = REALABS(QUAD_TO_DBL(coef));
5737 newfj = fj;
5738 }
5739 else
5740 {
5741 fj = SCIPfrac(scip, varsign[i] * QUAD_TO_DBL(coef));
5742 newfj = SCIPfrac(scip, -varsign[i] * QUAD_TO_DBL(coef));
5743 }
5744
5745 if( !ignoresol )
5746 {
5747 solval = SCIPgetSolVal(scip, sol, data->vars[v]);
5748 viol = f0 - fj * (varsign[i] == +1 ? solval - bestlbs[i] : bestubs[i] - solval);
5749 newviol = newf0 - newfj * (varsign[i] == -1 ? solval - bestlbs[i] : bestubs[i] - solval);
5750 violgain = newviol - viol;
5751 }
5752 else
5753 {
5754 /* todo: this should be done, this can improve the dualray significantly */
5755 SCIPerrorMessage("Cannot handle closest bounds with ignoring the LP solution.\n");
5756 return SCIP_INVALIDCALL;
5757 }
5758
5759 /* prefer larger violations; for equal violations, prefer smaller f0 values since then the possibility that
5760 * we f_j > f_0 is larger and we may improve some coefficients in rounding
5761 */
5762 if( SCIPisGT(scip, violgain, bestviolgain) || (SCIPisGE(scip, violgain, bestviolgain) && newf0 < bestnewf0) )
5763 {
5764 besti = i;
5765 bestviolgain = violgain;
5766 bestnewf0 = newf0;
5767 }
5768 }
5769 }
5770
5771 if( besti >= 0 )
5772 {
5773 SCIP_Real QUAD(tmp);
5774
5775 assert(besti < data->ncutinds);
5776 assert(boundtype[besti] < 0);
5777 assert(!SCIPisInfinity(scip, -bestlbs[besti]));
5778 assert(!SCIPisInfinity(scip, bestubs[besti]));
5779
5780 QUAD_ARRAY_LOAD(coef, data->cutcoefs, data->cutinds[besti]);
5781 QUAD_SCALE(coef, varsign[besti]);
5782
5783 /* switch the complementation of this variable */
5784 SCIPquadprecSumDD(tmp, bestlbs[besti], - bestubs[besti]);
5785 SCIPquadprecProdQQ(tmp, tmp, coef);
5786 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
5787
5788 if( varsign[besti] == +1 )
5789 {
5790 /* switch to upper bound */
5791 assert(bestubtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
5792 boundtype[besti] = bestubtypes[besti];
5793 varsign[besti] = -1;
5794 }
5795 else
5796 {
5797 /* switch to lower bound */
5798 assert(bestlbtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
5799 boundtype[besti] = bestlbtypes[besti];
5800 varsign[besti] = +1;
5801 }
5802 *localbdsused = *localbdsused || (boundtype[besti] == -2);
5803 }
5804 }
5805 }
5806
5807 TERMINATE:
5808
5809 /*free temporary memory */
5810 SCIPfreeBufferArray(scip, &selectedbounds);
5811 SCIPfreeBufferArray(scip, &bestubtypes);
5812 SCIPfreeBufferArray(scip, &bestlbtypes);
5813 SCIPfreeBufferArray(scip, &bestubs);
5814 SCIPfreeBufferArray(scip, &bestlbs);
5815
5816 return SCIP_OKAY;
5817}
5818
5819/** 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$
5820 * \f[
5821 * \begin{array}{rll}
5822 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
5823 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
5824 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
5825 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
5826 * \end{array}
5827 * \f]
5828 *
5829 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
5830 *
5831 * (lb or ub):
5832 * \f[
5833 * \begin{array}{lllll}
5834 * 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}, \\
5835 * 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},
5836 * \end{array}
5837 * \f]
5838 * and move the constant terms
5839 * \f[
5840 * \begin{array}{cl}
5841 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
5842 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
5843 * \end{array}
5844 * \f]
5845 * to the rhs.
5846 *
5847 * (vlb or vub):
5848 * \f[
5849 * \begin{array}{lllll}
5850 * 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)} \\
5851 * 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)}
5852 * \end{array}
5853 * \f]
5854 * move the constant terms
5855 * \f[
5856 * \begin{array}{cl}
5857 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
5858 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
5859 * \end{array}
5860 * \f]
5861 * to the rhs, and update the VB variable coefficients:
5862 * \f[
5863 * \begin{array}{ll}
5864 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
5865 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
5866 * \end{array}
5867 * \f]
5868 *
5869 * @note this method is safe for usage in exact solving mode
5870 */
5871static
5873 SCIP* scip, /**< SCIP data structure */
5874 SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
5875 SCIP_Real*RESTRICT cutrhs, /**< pointer to right hand side of cut */
5876 int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
5877 int*RESTRICT nnz, /**< number of non-zeros in cut */
5878 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
5879 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
5880 SCIP_INTERVAL f0 /**< fractional value of rhs */
5881 )
5882{
5883 SCIP_INTERVAL onedivoneminusf0;
5884 int i;
5885 int firstcontvar;
5886 SCIP_VAR** vars;
5887 int ndelcontvars;
5888 SCIP_ROUNDMODE previousroundmode;
5889 SCIP_MIRINFO* mirinfo = NULL;
5890 SCIP_INTERVAL tmpinterval;
5891
5892 assert(cutrhs != NULL);
5893 assert(cutcoefs != NULL);
5894 assert(cutinds != NULL);
5895 assert(nnz != NULL);
5896 assert(boundtype != NULL);
5897 assert(varsign != NULL);
5898 assert(0.0 < SCIPintervalGetInf(f0) && SCIPintervalGetSup(f0) < 1.0);
5899 assert(SCIPisExact(scip));
5900
5901 /* round up at first, since we are dividing and divisor should be as large as possible,
5902 * then switch to down since we are working on lhs */
5903 /* 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 */
5904 if( SCIPisCertified(scip) )
5906
5907 previousroundmode = SCIPintervalGetRoundingMode();
5908 tmpinterval = f0;
5910 SCIPintervalAddScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, 1.0);
5911 SCIPintervalSet(&onedivoneminusf0, 1.0);
5912 SCIPintervalDiv(SCIPinfinity(scip), &onedivoneminusf0, onedivoneminusf0, tmpinterval);
5914
5915 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
5916 * without destroying the ordering of the aggrrow's non-zeros.
5917 * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
5918 */
5919
5920 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5921 vars = SCIPgetVars(scip);
5922#ifndef NDEBUG
5923 /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
5924 i = 0;
5925 while( i < *nnz && cutinds[i] >= firstcontvar )
5926 ++i;
5927
5928 while( i < *nnz )
5929 {
5930 assert(cutinds[i] < firstcontvar);
5931 ++i;
5932 }
5933#endif
5934
5935 /* round down everything on lhs (excepts for the denominator part above) */
5937
5938 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
5939 {
5940 SCIP_VAR* var;
5941 SCIP_INTERVAL cutaj;
5942
5943 int v;
5944
5945 v = cutinds[i];
5946 assert(0 <= v && v < SCIPgetNVars(scip));
5947
5948 var = vars[v];
5949 assert(var != NULL);
5950 assert(SCIPvarGetProbindex(var) == v);
5951 assert(varsign[i] == +1 || varsign[i] == -1);
5952
5953 /* work on lhs -> round down */
5955
5956 /* calculate the coefficient in the retransformed cut */
5957 {
5958 SCIP_Real aj;
5959 SCIP_Real downaj;
5960 SCIP_Real fj;
5961
5962 aj = cutcoefs[v] * varsign[i];
5963
5964 downaj = floor(aj);
5965 fj = aj - downaj;
5966 assert(fj >= -SCIPepsilon(scip) && fj <= 1.0);
5967
5968 if( SCIPisLE(scip, fj, SCIPintervalGetInf(f0)) )
5969 {
5970 SCIPintervalSet(&cutaj, downaj);
5971
5972 if( SCIPisCertified(scip) && mirinfo != NULL )
5973 {
5974 SCIP_RATIONAL* boundval;
5975
5976 mirinfo->splitcoefficients[v] = SCIPintervalGetInf(cutaj); /*lint !e644*/
5977 assert(!SCIPisInfinity(scip, fabs(cutaj.inf)));
5978 if( mirinfo->upperused[v] )
5979 {
5980 mirinfo->splitcoefficients[v] *= -1;
5981 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
5982 }
5983 else
5984 {
5985 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
5986 }
5987 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
5988 }
5989 }
5990 else
5991 {
5992 SCIPintervalSet(&tmpinterval, aj);
5993 SCIPintervalSubScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, downaj);
5994 SCIPintervalSub(SCIPinfinity(scip), &tmpinterval, tmpinterval, f0);
5995 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, onedivoneminusf0);
5996 SCIPintervalAddScalar(SCIPinfinity(scip), &cutaj, tmpinterval, downaj);
5997
5998 if( SCIPisCertified(scip) && mirinfo != NULL )
5999 {
6000 SCIP_RATIONAL* boundval;
6001 mirinfo->splitcoefficients[v] = downaj;
6002 mirinfo->splitcoefficients[v] += 1.0;
6003 if( mirinfo->upperused[v] )
6004 {
6005 mirinfo->splitcoefficients[v] *= -1;
6006 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
6007 }
6008 else
6009 {
6010 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
6011 }
6012 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
6013 }
6014 }
6015
6016 SCIPintervalMulScalar(SCIPinfinity(scip), &cutaj, cutaj, (double) varsign[i]);
6017 }
6018
6019 /* integral var uses standard bound */
6020 assert(boundtype[i] < 0);
6021
6022 if( cutaj.inf != 0.0 || cutaj.sup != 0 )
6023 {
6024 /* we have to use the inf of the cutaj-interval both times! */
6026
6027 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6028 if( varsign[i] == +1 )
6029 {
6030 /* lower bound was used */
6031 if( boundtype[i] == -1 )
6032 {
6034 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
6036 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6037 *cutrhs += SCIPintervalGetSup(tmpinterval);
6038 }
6039 else
6040 {
6041 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
6043 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6044 *cutrhs += SCIPintervalGetSup(tmpinterval);
6045 }
6046 }
6047 else
6048 {
6049 /* upper bound was used */
6050 if( boundtype[i] == -1 )
6051 {
6053 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
6055 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6056 *cutrhs += SCIPintervalGetSup(tmpinterval);
6057 }
6058 else
6059 {
6060 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6062 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6063 *cutrhs += SCIPintervalGetSup(tmpinterval);
6064 }
6065 }
6066 }
6067
6068 /* remove zero cut coefficients from cut, only remove exactly 0 in exact solving mode
6069 * we can only do this here, since the sup might be positive and impact the rhs of the cut */
6070 if( cutaj.inf == 0.0 )
6071 {
6072 cutcoefs[v] = 0.0;
6073 --*nnz;
6074 cutinds[i] = cutinds[*nnz];
6075 continue;
6076 }
6077
6078 cutcoefs[v] = SCIPintervalGetInf(cutaj);
6079 }
6080
6081 /* adapt lhs -> round down */
6083
6084 /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
6085 ndelcontvars = 0;
6086 while( i >= ndelcontvars )
6087 {
6088 SCIP_VAR* var;
6089 SCIP_INTERVAL cutaj;
6090 SCIP_Real aj;
6091 int v;
6092
6093 v = cutinds[i];
6094 assert(0 <= v && v < SCIPgetNVars(scip));
6095
6096 var = vars[v];
6097 assert(var != NULL);
6098 assert(SCIPvarGetProbindex(var) == v);
6099 assert(varsign[i] == +1 || varsign[i] == -1);
6100 assert( v >= firstcontvar );
6101
6102 /* adapt lhs -> round down */
6104
6105 /* calculate the coefficient in the retransformed cut */
6106 aj = cutcoefs[v];
6107
6108 if( aj * varsign[i] >= 0.0 )
6109 SCIPintervalSet(&cutaj, 0.0);
6110 else
6111 {
6112 SCIPintervalMulScalar(SCIPinfinity(scip), &cutaj, onedivoneminusf0, aj); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
6113 }
6114
6115 /* remove zero cut coefficients from cut; move a continuous var from the beginning
6116 * to the current position, so that all integral variables stay behind the continuous
6117 * variables
6118 */
6119 if( EPSZ(SCIPintervalGetInf(cutaj), QUAD_EPSILON) && (SCIPintervalGetInf(cutaj) >= 0.0) )
6120 {
6121 SCIPintervalSet(&cutaj, 0.0);
6122 cutcoefs[v] = 0.0;
6123 cutinds[i] = cutinds[ndelcontvars];
6124 varsign[i] = varsign[ndelcontvars];
6125 boundtype[i] = boundtype[ndelcontvars];
6126 ++ndelcontvars;
6127 continue;
6128 }
6129
6130 cutcoefs[v] = SCIPintervalGetInf(cutaj);
6131
6133
6134 /* check for variable bound use */
6135 if( boundtype[i] < 0 )
6136 {
6137 /* standard bound */
6138
6139 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6140 if( varsign[i] == +1 )
6141 {
6142 /* lower bound was used */
6143 if( boundtype[i] == -1 )
6144 {
6145 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
6147 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6148 *cutrhs += SCIPintervalGetSup(tmpinterval);
6149 }
6150 else
6151 {
6152 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
6154 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6155 *cutrhs += SCIPintervalGetSup(tmpinterval);
6156 }
6157 }
6158 else
6159 {
6160 /* upper bound was used */
6161 if( boundtype[i] == -1 )
6162 {
6163 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
6165 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6166 *cutrhs += SCIPintervalGetSup(tmpinterval);
6167 }
6168 else
6169 {
6170 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6172 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
6173 *cutrhs += SCIPintervalGetSup(tmpinterval);
6174 }
6175 }
6176 }
6177 else
6178 {
6179 SCIPerrorMessage("varbounds not yet implemented in exact SCIP \n");
6180 return SCIP_ERROR;
6181 }
6182
6183 /* advance to next variable */
6184 --i;
6185 }
6186
6187 /* fill the empty position due to deleted continuous variables */
6188 if( ndelcontvars > 0 )
6189 {
6190 assert(ndelcontvars <= *nnz);
6191 *nnz -= ndelcontvars;
6192 if( *nnz < ndelcontvars )
6193 {
6194 BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
6195 }
6196 else
6197 {
6198 BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
6199 }
6200 }
6201
6202 /* reset rounding mode, also set the rhs->data in the mirinfo */
6203 SCIPintervalSetRoundingMode(previousroundmode);
6204
6205 return SCIP_OKAY;
6206}
6207
6208#ifdef SCIP_DISABLED_CODE
6209/** 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$
6210 * \f[
6211 * \begin{array}{rll}
6212 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
6213 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
6214 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
6215 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
6216 * \end{array}
6217 * \f]
6218 *
6219 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
6220 *
6221 * (lb or ub):
6222 * \f[
6223 * \begin{array}{lllll}
6224 * 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} \\
6225 * 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}
6226 * \end{array}
6227 * \f]
6228 * and move the constant terms
6229 * \f[
6230 * \begin{array}{cl}
6231 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
6232 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
6233 * \end{array}
6234 * \f]
6235 * to the rhs.
6236 *
6237 * (vlb or vub):
6238 * \f[
6239 * \begin{array}{lllll}
6240 * 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)} \\
6241 * 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)}
6242 * \end{array}
6243 * \f]
6244 * move the constant terms
6245 * \f[
6246 * \begin{array}{cl}
6247 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
6248 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
6249 * \end{array}
6250 * \f]
6251 * to the rhs, and update the VB variable coefficients:
6252 * \f[
6253 * \begin{array}{ll}
6254 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
6255 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
6256 * \end{array}
6257 * \f]
6258 *
6259 * @note this method is safe for usage in exact solving mode
6260 */
6261static
6262SCIP_RETCODE cutsRoundMIRRational(
6263 SCIP* scip, /**< SCIP data structure */
6264 SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
6265 QUAD(SCIP_Real*RESTRICT cutrhs), /**< pointer to right hand side of cut */
6266 int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
6267 int*RESTRICT nnz, /**< number of non-zeros in cut */
6268 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
6269 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
6270 SCIP_RATIONAL* f0 /**< fractional value of rhs */
6271 )
6272{
6273 SCIP_RATIONAL* tmp;
6274 SCIP_RATIONAL* onedivoneminusf0;
6275 int i;
6276 int firstcontvar;
6277 SCIP_VAR** vars;
6278 int ndelcontvars;
6279 SCIP_ROUNDMODE previousroundmode;
6280 SCIP_MIRINFO* mirinfo;
6281
6282 assert(QUAD_HI(cutrhs) != NULL);
6283 assert(cutcoefs != NULL);
6284 assert(cutinds != NULL);
6285 assert(nnz != NULL);
6286 assert(boundtype != NULL);
6287 assert(varsign != NULL);
6288 assert(SCIPrationalIsPositive(f0) && SCIPrationalIsLTReal(f0, 1.0));
6289 assert(SCIPisExact(scip));
6290
6291 SCIP_CALL( SCIPrationalCreateBuffer(SCIPbuffer(scip), &onedivoneminusf0) );
6293
6294 /* round up at first, since we are dividing and divisor should be as large as possible,
6295 * then switch to down since we are working on lhs */
6296 /* 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 */
6297 if( SCIPisCertified(scip) )
6299
6300 previousroundmode = SCIPintervalGetRoundingMode();
6301 SCIPrationalSetReal(tmp, 1.0);
6302 SCIPrationalDiff(tmp, tmp, f0);
6303 SCIPrationalSetReal(onedivoneminusf0, 1.0);
6304 SCIPrationalDiv(onedivoneminusf0, onedivoneminusf0, tmp);
6305
6306 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
6307 * without destroying the ordering of the aggrrow's non-zeros.
6308 * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
6309 */
6310
6311 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
6312 vars = SCIPgetVars(scip);
6313#ifndef NDEBUG
6314 /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
6315 i = 0;
6316 while( i < *nnz && cutinds[i] >= firstcontvar )
6317 ++i;
6318
6319 while( i < *nnz )
6320 {
6321 assert(cutinds[i] < firstcontvar);
6322 ++i;
6323 }
6324#endif
6325
6326 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
6327 {
6328 SCIP_VAR* var;
6329 SCIP_RATIONAL* cutaj;
6330 SCIP_Real QUAD(cutajquad);
6331 int v;
6332
6333 v = cutinds[i];
6334 assert(0 <= v && v < SCIPgetNVars(scip));
6335
6337
6338 var = vars[v];
6339 assert(var != NULL);
6340 assert(SCIPvarGetProbindex(var) == v);
6341 assert(varsign[i] == +1 || varsign[i] == -1);
6342
6343 /* calculate the coefficient in the retransformed cut */
6344 {
6345 SCIP_Real QUAD(aj);
6346 SCIP_Real downaj;
6347 SCIP_RATIONAL* fj;
6348
6350
6351 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
6352 QUAD_SCALE(aj, varsign[i]);
6353 SCIPrationalSetReal(tmp, aj);
6354
6355 downaj = floor(QUAD_TO_DBL(aj));
6356 SCIPrationalDiffReal(fj, tmp, downaj);
6357
6358 if( SCIPrationalIsLE(fj, f0) )
6359 {
6360 SCIPrationalSetReal(cutaj, downaj);
6361
6362 if( SCIPisCertified(scip) )
6363 {
6364 SCIP_RATIONAL* boundval;
6365
6366 mirinfo->splitcoefficients[v] = downaj;
6367 if( mirinfo->upperused[v] )
6368 {
6369 mirinfo->splitcoefficients[v] *= -1;
6370 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
6371 }
6372 else
6373 {
6374 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
6375 }
6376 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
6377 }
6378 }
6379 else
6380 {
6382 SCIPrationalDiffReal(tmp, tmp, downaj);
6383 SCIPrationalDiff(tmp, tmp, f0);
6384 SCIPrationalMult(tmp, tmp, onedivoneminusf0);
6385 SCIPrationalAddReal(cutaj, tmp, downaj);
6386
6387 if( SCIPisCertified(scip) )
6388 {
6389 SCIP_RATIONAL* boundval;
6390
6391 mirinfo->splitcoefficients[v] = QUAD_TO_DBL(downaj);
6392 mirinfo->splitcoefficients[v] += 1.0;
6393 if( mirinfo->upperused[v] )
6394 {
6395 mirinfo->splitcoefficients[v] *= -1;
6396 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
6397 }
6398 else
6399 {
6400 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
6401 }
6402 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
6403 }
6404 }
6405
6406 SCIPrationalMultReal(cutaj, cutaj, varsign[i]);
6407
6409 }
6410
6411 /* remove zero cut coefficients from cut, only remove positive coefficients in exact solving mode */
6412 if( SCIPrationalIsZero(cutaj) )
6413 {
6414 QUAD_ASSIGN(cutajquad, 0.0);
6415 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
6416 --*nnz;
6417 cutinds[i] = cutinds[*nnz];
6419 continue;
6420 }
6421
6423
6424 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
6425
6426 /* integral var uses standard bound */
6427 assert(boundtype[i] < 0);
6428
6430
6431 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6432 if( varsign[i] == +1 )
6433 {
6434 /* lower bound was used */
6435 if( boundtype[i] == -1 )
6436 {
6438 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
6439 SCIPrationalMult(tmp, cutaj, SCIPvarGetLbGlobalExact(var));
6440 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetLbGlobal(var) */
6441 }
6442 else
6443 {
6444 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
6445 SCIPrationalMult(tmp, cutaj, SCIPvarGetLbLocalExact(var));
6446 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetLbLocal(var) */
6447 }
6448 }
6449 else
6450 {
6451 /* upper bound was used */
6452 if( boundtype[i] == -1 )
6453 {
6455 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
6456 SCIPrationalMult(tmp, cutaj, SCIPvarGetUbGlobalExact(var));
6457 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetUbGlobal(var) */
6458 }
6459 else
6460 {
6461 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6462 SCIPrationalMult(tmp, cutaj, SCIPvarGetUbLocalExact(var));
6463 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetUbLocal(var) */
6464 }
6465 }
6467 }
6468
6469 /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
6470 ndelcontvars = 0;
6471 while( i >= ndelcontvars )
6472 {
6473 SCIP_VAR* var;
6474 SCIP_RATIONAL* cutaj;
6475 SCIP_RATIONAL* tmprational;
6476 SCIP_Real QUAD(cutajquad);
6477 SCIP_Real QUAD(aj);
6478 int v;
6479
6480 /* adapt lhs -> round down */
6482
6485
6486 v = cutinds[i];
6487 assert(0 <= v && v < SCIPgetNVars(scip));
6488
6489 var = vars[v];
6490 assert(var != NULL);
6491 assert(SCIPvarGetProbindex(var) == v);
6492 assert(varsign[i] == +1 || varsign[i] == -1);
6493 assert( v >= firstcontvar );
6494
6495 /* calculate the coefficient in the retransformed cut */
6496 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
6497
6498 if( QUAD_TO_DBL(aj) * varsign[i] >= 0.0 )
6499 SCIPrationalSetReal(cutaj, 0.0);
6500 else
6501 {
6502 SCIPrationalSetRational(cutaj, onedivoneminusf0);
6503 SCIPrationalMultReal(cutaj, cutaj, QUAD_TO_DBL(aj)); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
6504 }
6505
6506 /* remove zero cut coefficients from cut; move a continuous var from the beginning
6507 * to the current position, so that all integral variables stay behind the continuous
6508 * variables
6509 */
6510 if( EPSZ(SCIPrationalGetReal(cutaj), QUAD_EPSILON) && SCIPrationalIsGEReal(cutaj, 0.0) )
6511 {
6512 assert(SCIPrationalIsZero(cutaj));
6513 SCIPrationalSetReal(cutaj, 0.0);
6514 QUAD_ASSIGN_Q(cutajquad, 0.0);
6515 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
6516 cutinds[i] = cutinds[ndelcontvars];
6517 varsign[i] = varsign[ndelcontvars];
6518 boundtype[i] = boundtype[ndelcontvars];
6519 ++ndelcontvars;
6520
6521 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
6523
6524 continue;
6525 }
6526
6528 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
6529
6531
6532 /* check for variable bound use */
6533 if( boundtype[i] < 0 )
6534 {
6535 /* standard bound */
6536
6537 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6538 if( varsign[i] == +1 )
6539 {
6540 /* lower bound was used */
6541 if( boundtype[i] == -1 )
6542 {
6544 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
6545 SCIPrationalMult(tmprational, cutaj, SCIPvarGetLbGlobalExact(var));
6546 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
6547 }
6548 else
6549 {
6550 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
6551 SCIPrationalMult(tmprational, cutaj, SCIPvarGetLbLocalExact(var));
6552 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
6553 }
6554 }
6555 else
6556 {
6557 /* upper bound was used */
6558 if( boundtype[i] == -1 )
6559 {
6561 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
6562 SCIPrationalMult(tmprational, cutaj, SCIPvarGetUbGlobalExact(var));
6563 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
6564 }
6565 else
6566 {
6567 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6568 SCIPrationalMult(tmprational, cutaj, SCIPvarGetUbLocalExact(var));
6569 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
6570 }
6571 }
6572
6573 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
6575 }
6576 else
6577 {
6578#ifdef SCIP_DISABLED_CODE
6579 SCIP_VAR** vbz;
6580 SCIP_Real* vbb;
6581 SCIP_Real* vbd;
6582 SCIP_Real QUAD(zcoef);
6583 int vbidx;
6584 int zidx;
6585
6586 assert(!SCIPisExact(scip));
6587
6588 /* variable bound */
6589 vbidx = boundtype[i];
6590
6591 /* change mirrhs and cutaj of integer variable z_j of variable bound */
6592 if( varsign[i] == +1 )
6593 {
6594 /* variable lower bound was used */
6595 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
6596 vbz = SCIPvarGetVlbVars(var);
6597 vbb = SCIPvarGetVlbCoefs(var);
6598 vbd = SCIPvarGetVlbConstants(var);
6599 }
6600 else
6601 {
6602 /* variable upper bound was used */
6603 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
6604 vbz = SCIPvarGetVubVars(var);
6605 vbb = SCIPvarGetVubCoefs(var);
6606 vbd = SCIPvarGetVubConstants(var);
6607 }
6608 assert(SCIPvarIsActive(vbz[vbidx]));
6609 zidx = SCIPvarGetProbindex(vbz[vbidx]);
6610 assert(0 <= zidx && zidx < firstcontvar);
6611
6612 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
6613 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
6614
6615 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
6616 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
6617
6618 /* update sparsity pattern */
6619 if( QUAD_HI(zcoef) == 0.0 )
6620 cutinds[(*nnz)++] = zidx;
6621
6622 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
6623 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
6624 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
6625 assert(QUAD_HI(zcoef) != 0.0);
6626#endif
6627 }
6628
6629 /* advance to next variable */
6630 --i;
6631 }
6632
6633 /* fill the empty position due to deleted continuous variables */
6634 if( ndelcontvars > 0 )
6635 {
6636 assert(ndelcontvars <= *nnz);
6637 *nnz -= ndelcontvars;
6638 if( *nnz < ndelcontvars )
6639 {
6640 BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
6641 }
6642 else
6643 {
6644 BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
6645 }
6646 }
6647
6648 /* reset rounding mode, also set the rhs->data in the mirinfo */
6649 SCIPintervalSetRoundingMode(previousroundmode);
6650
6652 SCIPrationalFreeBuffer(SCIPbuffer(scip), &onedivoneminusf0);
6653
6654 return SCIP_OKAY;
6655}
6656#endif
6657
6658
6659/** 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$
6660 * \f[
6661 * \begin{array}{rll}
6662 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
6663 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
6664 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
6665 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
6666 * \end{array}
6667 * \f]
6668 *
6669 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
6670 *
6671 * (lb or ub):
6672 * \f[
6673 * \begin{array}{lllll}
6674 * 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} \\
6675 * 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}
6676 * \end{array}
6677 * \f]
6678 * and move the constant terms
6679 * \f[
6680 * \begin{array}{cl}
6681 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
6682 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
6683 * \end{array}
6684 * \f]
6685 * to the rhs.
6686 *
6687 * (vlb or vub):
6688 * \f[
6689 * \begin{array}{lllll}
6690 * 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)} \\
6691 * 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)}
6692 * \end{array}
6693 * \f]
6694 * move the constant terms
6695 * \f[
6696 * \begin{array}{cl}
6697 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
6698 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
6699 * \end{array}
6700 * \f]
6701 * to the rhs, and update the VB variable coefficients:
6702 * \f[
6703 * \begin{array}{ll}
6704 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
6705 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
6706 * \end{array}
6707 * \f]
6708 */
6709static
6711 SCIP* scip, /**< SCIP data structure */
6712 MIR_DATA* data, /**< the MIR data structure for this cut */
6713 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
6714 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
6715 QUAD(SCIP_Real f0) /**< fractional value of rhs */
6716 )
6717{
6718 SCIP_Real QUAD(tmp);
6719 SCIP_Real QUAD(onedivoneminusf0);
6720 int s;
6721 int cutindex;
6722 int i;
6723
6724 assert(data != NULL);
6725 assert(boundtype != NULL);
6726 assert(varsign != NULL);
6727 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
6728
6729 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
6730 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
6731
6732 /* Loop backwards through the sections, so that the reversing of varbound substitutions does not prematurely effect
6733 * the coefficients of variables in other sections, because the section index of a variable bound must always be
6734 * higher than that of the bounded variable. */
6735 cutindex = data->ncutinds - 1;
6736 for( s = NSECTIONS - 1; s >= 0; --s )
6737 {
6738 int* indices = data->secindices[s];
6739 int nnz = data->secnnz[s];
6740
6741 SCIP_Bool enfintegral = data->isenfint[s];
6742 SCIP_Bool implintegral = data->isimplint[s];
6743
6744 /* iterate backwards over indices in section, so we can easily shrink the section if we find zeros */
6745 for( i = nnz - 1; i >= 0 ; --i )
6746 {
6747 int v;
6748 int sign;
6749 int type;
6750 SCIP_Real QUAD(cutaj);
6751 SCIP_Real QUAD(aj);
6752 SCIP_VAR* var;
6753
6754 v = indices[i];
6755 assert(0 <= v && v < data->nvars);
6756 assert(data->cutinds[cutindex] == v);
6757
6758 sign = varsign[cutindex];
6759 assert(sign == +1 || sign == -1);
6760 type = boundtype[cutindex];
6761
6762 --cutindex;
6763
6764 var = data->vars[v];
6765 assert(var != NULL);
6766 assert(SCIPvarGetProbindex(var) == v );
6767
6768 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
6769
6770 if( enfintegral || implintegral )
6771 {
6772 /* variable is integral */
6773 SCIP_Real QUAD(downaj);
6774 SCIP_Real QUAD(fj);
6775
6776 QUAD_SCALE(aj, sign);
6777
6778 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
6779 SCIPquadprecSumQQ(fj, aj, -downaj);
6780 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
6781
6782 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
6783 {
6784 QUAD_ASSIGN_Q(cutaj, downaj); /* a^_j */
6785 }
6786 else
6787 {
6788 SCIPquadprecSumQQ(tmp, fj, -f0);
6789 SCIPquadprecProdQQ(tmp, tmp, onedivoneminusf0);
6790 SCIPquadprecSumQQ(cutaj, tmp, downaj);
6791 }
6792 QUAD_SCALE(cutaj, sign);
6793 }
6794 else
6795 {
6796 /* variable is continuous */
6798
6799 if( QUAD_TO_DBL(aj) * sign >= 0.0 )
6800 QUAD_ASSIGN(cutaj, 0.0);
6801 else
6802 SCIPquadprecProdQQ(cutaj, onedivoneminusf0, aj); /* cutaj = aj * onedivoneminusf0 */
6803 }
6804
6805 /* remove coefficient from cut if it becomes zero */
6806 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
6807 {
6808 QUAD_ASSIGN(cutaj, 0.0);
6809 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
6810 --data->totalnnz;
6811 --data->secnnz[s];
6812 indices[i] = indices[data->secnnz[s]];
6813 continue;
6814 }
6815
6816 /* store the updated coefficient */
6817 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
6818
6819 /* undo bound transformations */
6820 if( type < 0 )
6821 {
6822 /* standard bound */
6823 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
6824 if( sign == +1 )
6825 {
6826 /* lower bound was used */
6827 if( type == -1 )
6828 {
6829 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
6830 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
6831 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6832 }
6833 else
6834 {
6835 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
6836 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
6837 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6838 }
6839 }
6840 else
6841 {
6842 /* upper bound was used */
6843 if( type == -1 )
6844 {
6845 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
6846 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
6847 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6848 }
6849 else
6850 {
6851 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6852 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
6853 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6854 }
6855 }
6856 }
6857 else
6858 {
6859 /* variable bound */
6860 SCIP_VAR** vbz;
6861 SCIP_Real* vbb;
6862 SCIP_Real* vbd;
6863 SCIP_Real QUAD(zcoef);
6864 int vbidx;
6865 int zidx;
6866
6867 /* variable bound */
6868 vbidx = type;
6869
6870 /* change mirrhs and cutaj of integer variable z_j of variable bound */
6871 if( sign == +1 )
6872 {
6873 /* variable lower bound was used */
6874 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
6875 vbz = SCIPvarGetVlbVars(var);
6876 vbb = SCIPvarGetVlbCoefs(var);
6877 vbd = SCIPvarGetVlbConstants(var);
6878 }
6879 else
6880 {
6881 /* variable upper bound was used */
6882 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
6883 vbz = SCIPvarGetVubVars(var);
6884 vbb = SCIPvarGetVubCoefs(var);
6885 vbd = SCIPvarGetVubConstants(var);
6886 }
6887 assert(SCIPvarIsActive(vbz[vbidx]));
6888 zidx = SCIPvarGetProbindex(vbz[vbidx]);
6889 assert(varSection(data, zidx) > s);
6890
6891 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
6892 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
6893
6894 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
6895 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
6896
6897 /* update sparsity pattern */
6898 if( QUAD_HI(zcoef) == 0.0 )
6899 {
6900 int zsection = varSection(data, zidx);
6901 data->secindices[zsection][data->secnnz[zsection]] = zidx;
6902 ++data->secnnz[zsection];
6903 ++data->totalnnz;
6904 }
6905
6906 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
6907 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
6908 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
6909 assert(QUAD_HI(zcoef) != 0.0);
6910 }
6911 }
6912 }
6913
6914 /* Finally, store the relevant data in cutinds which is the array used by the other functions */
6915 data->ncutinds = 0;
6916 for( s = 0; s < NSECTIONS; ++s )
6917 {
6918 int* indices = data->secindices[s];
6919 int nnz = data->secnnz[s];
6920 for( i = 0; i < nnz; ++i )
6921 {
6922 data->cutinds[data->ncutinds] = indices[i];
6923 ++data->ncutinds;
6924 }
6925 }
6926 return SCIP_OKAY;
6927}
6928
6929/** substitute aggregated slack variables:
6930 *
6931 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
6932 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r]. \f$
6933 *
6934 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
6935 * \f[
6936 * \begin{array}{rll}
6937 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r \leq f_0 \\
6938 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f_0)/(1 - f_0),& \mbox{if}\qquad f_r > f_0 \\
6939 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r \geq 0 \\
6940 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f_0), & \mbox{if}\qquad a^\prime_r < 0
6941 * \end{array}
6942 * \f]
6943 *
6944 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
6945 *
6946 * @note this method is safe for usage in exact solving mode
6947 *
6948 * @todo certify and use integrality of row in exact solving mode
6949 *
6950 * @todo make behavior identical to the unsafe MIR cut computation
6951 */
6952static
6954 SCIP* scip, /**< SCIP data structure */
6955 SCIP_Real* weights, /**< row weights in row summation */
6956 int* slacksign, /**< stores the sign of the row's slack variable in summation */
6957 int* rowinds, /**< sparsity pattern of used rows */
6958 int nrowinds, /**< number of used rows */
6959 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
6960 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
6961 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
6962 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
6963 int* nnz, /**< number of non-zeros in cut */
6964 SCIP_INTERVAL f0 /**< fractional value of rhs */
6965 )
6966{ /*lint --e{715}*/
6967 SCIP_ROW** rows;
6968 SCIP_ROW* userow;
6969 SCIP_ROWEXACT* rowexact;
6970 SCIP_INTERVAL onedivoneminusf0, tmpinterval;
6971 SCIP_ROUNDMODE previousroundmode;
6972 SCIP_AGGREGATIONINFO* aggrinfo = NULL;
6973 SCIP_MIRINFO* mirinfo = NULL;
6974 SCIP_Real mult;
6975 SCIP_Real splitcoef;
6976 SCIP_Real slackweight;
6977 SCIP_Bool slackroundeddown;
6978 int i;
6979 int currentnegslackrow;
6980
6981 assert(scip != NULL);
6982 assert(weights != NULL || nrowinds == 0);
6983 assert(slacksign != NULL || nrowinds == 0);
6984 assert(rowinds != NULL || nrowinds == 0);
6985 assert(scale > 0.0);
6986 assert(cutcoefs != NULL);
6987 assert(cutrhs != NULL);
6988 assert(cutinds != NULL);
6989 assert(nnz != NULL);
6990 assert(0.0 < SCIPintervalGetInf(f0) && SCIPintervalGetSup(f0) < 1.0);
6991
6992 assert(SCIPisExact(scip));
6993
6994 /* compute 1/(1-f0) in interval arithmetic */
6995 previousroundmode = SCIPintervalGetRoundingMode();
6997 SCIPintervalAddScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, 1.0);
6998 SCIPintervalSet(&onedivoneminusf0, 1.0);
6999 SCIPintervalDiv(SCIPinfinity(scip), &onedivoneminusf0, onedivoneminusf0, tmpinterval);
7000
7001 if( SCIPisCertified(scip) )
7002 {
7005 }
7006
7007 rows = SCIPgetLPRows(scip);
7008 currentnegslackrow = 0;
7009 for( i = 0; i < nrowinds; i++ )
7010 {
7011 SCIP_ROW* row;
7012 SCIP_INTERVAL ar;
7013 SCIP_INTERVAL cutar;
7014 int r;
7015 SCIP_Bool integralslack = FALSE;
7016
7017 r = rowinds[i]; /*lint !e613*/
7018 assert(0 <= r && r < SCIPgetNLPRows(scip));
7019 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
7020 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
7021
7022 row = rows[r];
7023 assert(row != NULL);
7024 assert(row->len == 0 || row->cols != NULL);
7025 assert(row->len == 0 || row->cols_index != NULL);
7026 assert(row->len == 0 || row->vals != NULL);
7027
7028 if( slacksign[i] == 1 )
7030 else
7032
7033 /* get the slack's coefficient a'_r = weights[i] * scale in the aggregated row */
7034 SCIPintervalSet(&ar, weights[i]);
7035 SCIPintervalMulScalar(SCIPinfinity(scip), &ar, ar, scale);
7036 SCIPintervalMulScalar(SCIPinfinity(scip), &ar, ar, (double) slacksign[i]);
7037
7038 /* calculate slack variable's coefficient a^_r in the cut */
7039 if( row->integral &&
7040 ((slacksign[i] == +1 && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant))
7041 || (slacksign[i] == -1 && SCIPrealIsExactlyIntegral(row->lhs) && SCIPrealIsExactlyIntegral(row->constant))) ) /*lint !e613*/
7042 {
7043 /* slack variable is always integral:
7044 * a^_r = a~_r = down(a'_r) , if f_r <= f0
7045 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
7046 */
7047 SCIP_Real downar;
7048 SCIP_INTERVAL fr;
7049
7050 SCIPdebugMessage("resubstituting integer slack for row %s\n", row->name);
7051 downar = floor(ar.inf);
7052 SCIPintervalSubScalar(SCIPinfinity(scip), &fr, ar, downar);
7053
7054 integralslack = TRUE;
7055
7056 if( SCIPisLE(scip, fr.inf, f0.inf) )
7057 {
7058 SCIPintervalSet(&cutar, downar);
7059 splitcoef = downar;
7060 slackweight = weights[i];
7061 slackroundeddown = TRUE;
7062 SCIPintervalMul(SCIPinfinity(scip), &fr, fr, onedivoneminusf0);
7063 SCIPdebugMessage("fractionality %g, f0 %g -> round down to %g\n", fr.inf, f0.inf, splitcoef);
7064 }
7065 else
7066 {
7067 SCIPintervalSetBounds(&cutar, ar.inf, ar.sup);
7068 SCIPintervalSubScalar(SCIPinfinity(scip), &cutar, cutar, downar);
7069 SCIPintervalSub(SCIPinfinity(scip), &cutar, cutar, f0);
7070 SCIPintervalMul(SCIPinfinity(scip), &cutar, cutar, onedivoneminusf0);
7071 SCIPintervalAddScalar(SCIPinfinity(scip), &cutar, cutar, downar);
7072 splitcoef = downar + 1;
7073 slackweight = weights[i];
7074 slackroundeddown = FALSE;
7075 SCIPdebugMessage("fractionality %g, f0 %g -> round up! splitcoef %g sub-coefficient %g", fr.inf, f0.inf, splitcoef, cutar.inf);
7076 }
7077 }
7078 else
7079 {
7080 /* slack variable is continuous:
7081 * a^_r = a~_r = 0 , if a'_r >= 0
7082 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
7083 */
7084 if( SCIPintervalGetInf(ar) >= 0.0 )
7085 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
7086 else
7087 {
7088 SCIPintervalMul(SCIPinfinity(scip), &cutar, onedivoneminusf0, ar); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
7089 SCIPdebugMessage("resubstituting negative continuous slack for row %s with coef %g\n", row->name, cutar.inf);
7090 }
7091 }
7092
7093 rowexact = SCIProwGetRowExact(row);
7094 assert(SCIProwExactHasFpRelax(rowexact));
7095 if( SCIProwExactGetRowRhs(rowexact) != NULL && slacksign[i] == 1.0 )
7096 userow = SCIProwExactGetRowRhs(rowexact);
7097 else
7098 userow = row;
7099
7100 SCIPintervalMulScalar(SCIPinfinity(scip), &cutar, cutar, (double) -slacksign[i]);
7101
7102 if( slacksign[i] == -1 )
7103 mult = cutar.inf;
7104 else
7105 mult = cutar.sup;
7106
7107 if( SCIPisCertified(scip) && integralslack) /*lint --e{644}*/
7108 {
7109 assert(mirinfo != NULL);
7110 /* save the value for the split disjunction for the integer slack and the continous part (for rounded up we
7111 * subtract 1-f); multiply by -slacksign (same as above) since slack = side - row
7112 */
7113 mirinfo->slackrows[mirinfo->nslacks] = userow;
7114 SCIP_CALL( SCIPcaptureRow(scip, userow) );
7115 mirinfo->slackcoefficients[mirinfo->nslacks] = splitcoef * (-slacksign[i]);
7116 mirinfo->slacksign[mirinfo->nslacks] = slacksign[i];
7117 assert(SCIPrealIsExactlyIntegral(splitcoef));
7118 mirinfo->slackweight[mirinfo->nslacks] = slackweight;
7119 mirinfo->slackscale[mirinfo->nslacks] = scale;
7120 mirinfo->slackusedcoef[mirinfo->nslacks] = mult;
7121
7122 /* save the value that goes into the certificate aggregation row (either downar or ar) */
7123 mirinfo->slackroundeddown[mirinfo->nslacks] = slackroundeddown;
7124 if( slackroundeddown )
7125 mirinfo->nrounddownslacks++;
7126 mirinfo->nslacks++;
7127 }
7128
7129 /* if the coefficient was reduced to zero, ignore the slack variable */
7130 if( EPSZ(SCIPintervalGetInf(cutar), QUAD_EPSILON) && (SCIPintervalGetInf(cutar) >= 0.0) )
7131 continue;
7132
7133 /* depending on the slack's sign, we have
7134 * - sign = 1: s = rhs - a^Tx >= 0
7135 * - sign = -1: s = lhs - a^Tx <= 0
7136 */
7137 {
7138 SCIP_Bool success = TRUE;
7139 SCIP_Real sidevalchg;
7140
7141 if( SCIPisCertified(scip) && !integralslack )
7142 {
7143 assert(aggrinfo != NULL);
7144 assert(aggrinfo->negslackweights[currentnegslackrow] == -weights[i]); /*lint !e777*/
7145 aggrinfo->substfactor[currentnegslackrow] = mult;
7146 currentnegslackrow++;
7147 }
7148
7149 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, cutinds, cutcoefs, nnz, userow, mult, &sidevalchg, &success) );
7150 assert(success);
7151
7152 /* move to rhs -> need to round up */
7154 *cutrhs += sidevalchg;
7155 }
7156
7157 /* move slack's constant to the right hand side */
7158 if( slacksign[i] == +1 ) /*lint !e613*/
7159 {
7160 SCIP_INTERVAL rowrhs;
7161
7163 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7164 assert(!SCIPisInfinity(scip, userow->rhs));
7165 SCIPintervalSet(&rowrhs, userow->rhs);
7166 SCIPintervalSubScalar(SCIPinfinity(scip), &rowrhs, rowrhs, userow->constant);
7167#ifdef SCIP_DISABLED_CODE
7168 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
7169 if( row->integral )
7170 {
7171 /* the right hand side was implicitly rounded down in row aggregation */
7172 QUAD_ASSIGN(rowrhs, floor(QUAD_TO_DBL(rowrhs)));
7173 }
7174#endif
7175 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, cutar, rowrhs);
7176 *cutrhs += SCIPintervalGetSup(tmpinterval);
7177 }
7178 else
7179 {
7180 SCIP_INTERVAL rowlhs;
7181
7183 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7184 assert(!SCIPisInfinity(scip, -userow->lhs));
7185 SCIPintervalSet(&rowlhs, userow->lhs);
7186 SCIPintervalSubScalar(SCIPinfinity(scip), &rowlhs, rowlhs, userow->constant);
7187#ifdef SCIP_DISABLED_CODE
7188 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
7189 if( row->integral )
7190 {
7191 /* the left hand side was implicitly rounded up in row aggregation */
7192 QUAD_ASSIGN(rowlhs, floor(QUAD_TO_DBL(rowlhs)));
7193 }
7194#endif
7195 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, cutar, rowlhs);
7196 *cutrhs += SCIPintervalGetSup(tmpinterval);
7197 }
7198 }
7199
7200 /* relax rhs to zero, if it's very close to 0 */
7201 if( *cutrhs < 0.0 && *cutrhs >= SCIPepsilon(scip) )
7202 *cutrhs = 0.0;
7203
7204 SCIPintervalSetRoundingMode(previousroundmode);
7205
7206 return SCIP_OKAY;
7207}
7208
7209#ifdef SCIP_DISABLED_CODE
7210/** substitute aggregated slack variables:
7211 *
7212 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
7213 * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
7214 *
7215 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
7216 * \f[
7217 * \begin{array}{rll}
7218 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
7219 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
7220 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
7221 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
7222 * \end{array}
7223 * \f]
7224 *
7225 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
7226 *
7227 * @note this method is safe for usage in exact solving mode
7228 */
7229static
7230SCIP_RETCODE cutsSubstituteMIRRational(
7231 SCIP* scip, /**< SCIP data structure */
7232 SCIP_Real* weights, /**< row weights in row summation */
7233 int* slacksign, /**< stores the sign of the row's slack variable in summation */
7234 int* rowinds, /**< sparsity pattern of used rows */
7235 int nrowinds, /**< number of used rows */
7236 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
7237 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7238 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
7239 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7240 int* nnz, /**< number of non-zeros in cut */
7241 SCIP_RATIONAL* f0 /**< fractional value of rhs */
7242 )
7243{ /*lint --e{715}*/
7244 SCIP_ROW** rows;
7245 SCIP_ROW* userow;
7246 SCIP_ROWEXACT* rowexact;
7247 SCIP_RATIONAL* onedivoneminusf0;
7248 SCIP_RATIONAL* tmprational;
7249 SCIP_ROUNDMODE previousroundmode;
7250 SCIP_AGGREGATIONINFO* aggrinfo;
7251 SCIP_Real mult;
7252 int i;
7253 int currentnegslackrow;
7254 SCIP_RATIONAL* ar;
7255 SCIP_RATIONAL* cutar;
7256 int r;
7257
7258 assert(scip != NULL);
7259 assert(weights != NULL || nrowinds == 0);
7260 assert(slacksign != NULL || nrowinds == 0);
7261 assert(rowinds != NULL || nrowinds == 0);
7262 assert(scale > 0.0);
7263 assert(cutcoefs != NULL);
7264 assert(QUAD_HI(cutrhs) != NULL);
7265 assert(cutinds != NULL);
7266 assert(nnz != NULL);
7267 assert(SCIPisExact(scip));
7268
7270 SCIP_CALL( SCIPrationalCreateBuffer(SCIPbuffer(scip), &onedivoneminusf0) );
7273
7274 /* compute 1/(1-f0) in interval arithmetic */
7275 previousroundmode = SCIPintervalGetRoundingMode();
7276 SCIPrationalMultReal(onedivoneminusf0, f0, -1);
7277 SCIPrationalAddReal(onedivoneminusf0, onedivoneminusf0, 1.0);
7278 SCIPrationalInvert(onedivoneminusf0, onedivoneminusf0);
7279
7280 if( SCIPisCertified(scip) )
7281 {
7283 }
7284
7285 rows = SCIPgetLPRows(scip);
7286 currentnegslackrow = 0;
7287 for( i = 0; i < nrowinds; i++ )
7288 {
7289 SCIP_ROW* row;
7290
7291 r = rowinds[i]; /*lint !e613*/
7292 assert(0 <= r && r < SCIPgetNLPRows(scip));
7293 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
7294 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
7295
7296 row = rows[r];
7297 assert(row != NULL);
7298 assert(row->len == 0 || row->cols != NULL);
7299 assert(row->len == 0 || row->cols_index != NULL);
7300 assert(row->len == 0 || row->vals != NULL);
7301
7302 if( slacksign[i] == 1 )
7304 else
7306
7307 /* get the slack's coefficient a'_r = weights[i] * scale in the aggregated row */
7308 SCIPrationalSetReal(ar, weights[i]);
7309 SCIPrationalMultReal(ar, ar, scale);
7310 SCIPrationalMultReal(ar, ar, slacksign[i]);
7311
7312 /* calculate slack variable's coefficient a^_r in the cut */
7313#ifdef SCIP_DISABLED_CODE
7314 if( row->integral && !SCIPisExact(scip)
7315 && ((slacksign[i] == +1 && SCIPisFeasIntegral(scip, row->rhs - row->constant))
7316 || (slacksign[i] == -1 && SCIPisFeasIntegral(scip, row->lhs - row->constant))) ) /*lint !e613*/
7317 {
7318 /* slack variable is always integral:
7319 * a^_r = a~_r = down(a'_r) , if f_r <= f0
7320 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
7321 */
7322 if( !SCIPisExact(scip) )
7323 downar = EPSFLOOR(ar, QUAD_EPSILON);
7324 else
7325 downar = floor(ar);
7326
7327 SCIPquadprecSumDD(fr, ar, -downar);
7328 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) && (!SCIPisExact(scip) || QUAD_TO_DBL(fr) <= QUAD_TO_DBL(f0)) )
7329 {
7330 QUAD_ASSIGN(cutar, downar);
7331 }
7332 else
7333 {
7334 SCIPquadprecSumQQ(cutar, fr, -f0);
7335 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
7336 SCIPquadprecSumQD(cutar, cutar, downar);
7337 }
7338 }
7339 else
7340#endif
7341 {
7342 /* slack variable is continuous:
7343 * a^_r = a~_r = 0 , if a'_r >= 0
7344 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
7345 */
7346 if( !SCIPrationalIsNegative(ar) )
7347 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
7348 else
7349 {
7350 SCIPrationalMult(cutar, ar, onedivoneminusf0); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
7351 }
7352 }
7353
7354 /* if the coefficient was reduced to zero, ignore the slack variable */
7355 if( SCIPrationalIsZero(cutar) )
7356 continue;
7357
7358 /* depending on the slack's sign, we have
7359 * sign = 1: s = rhs - a^Tx >= 0
7360 sign = -1: s = lhs - a^Tx <= 0
7361 */
7362
7363 rowexact = SCIProwGetRowExact(row);
7364 assert(SCIProwExactHasFpRelax(rowexact));
7365 if( SCIProwExactGetRowRhs(rowexact) != NULL && slacksign[i] == 1.0 )
7366 userow = SCIProwExactGetRowRhs(rowexact);
7367 else
7368 userow = row;
7369
7370 {
7371 SCIP_Bool success = TRUE;
7372 SCIP_Real sidevalchg;
7373
7374 SCIPrationalMultReal(cutar, cutar, -slacksign[i]);
7375 if( slacksign[i] == -1 )
7377 else
7379
7380 if( SCIPisCertified(scip) )
7381 {
7382 assert(aggrinfo->negslackweights[currentnegslackrow] == -weights[i]);
7383 aggrinfo->substfactor[currentnegslackrow] = mult;
7384 currentnegslackrow++;
7385 }
7386
7387 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, cutinds, cutcoefs, nnz, userow, mult, &sidevalchg, &success) );
7388 assert(success);
7389
7390 /* move to rhs -> need to round up */
7392 *cutrhs += sidevalchg;
7393 }
7394
7395 /* move slack's constant to the right hand side */
7396 if( slacksign[i] == +1 ) /*lint !e613*/
7397 {
7398 SCIP_INTERVAL valinterval;
7399 SCIP_INTERVAL cutarinterval;
7400
7402 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7403 assert(!SCIPisInfinity(scip, userow->rhs));
7404#ifdef SCIP_DISABLED_CODE
7405 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
7406 if( row->integral )
7407 {
7408 /* the right hand side was implicitly rounded down in row aggregation */
7409 QUAD_ASSIGN(rowrhs, floor(QUAD_TO_DBL(rowrhs)));
7410 }
7411#endif
7412 SCIPintervalSet(&valinterval, userow->rhs);
7413 SCIPintervalSubScalar(SCIPinfinity(scip), &valinterval, valinterval, userow->constant);
7414 SCIPintervalSetRational(&cutarinterval, cutar);
7415 SCIPintervalMul(SCIPinfinity(scip), &valinterval, valinterval, cutarinterval);
7416 SCIPquadprecSumQQ(*cutrhs, *cutrhs, SCIPintervalGetSup(valinterval));
7417 }
7418 else
7419 {
7420 SCIP_INTERVAL valinterval;
7421 SCIP_INTERVAL cutarinterval;
7422
7424 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7425 assert(!SCIPisInfinity(scip, -userow->lhs));
7426#ifdef SCIP_DISABLED_CODE
7427 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
7428 if( row->integral )
7429 {
7430 /* the left hand side was implicitly rounded up in row aggregation */
7431 QUAD_ASSIGN(rowlhs, floor(QUAD_TO_DBL(rowlhs)));
7432 }
7433#endif
7434 SCIPintervalSet(&valinterval, userow->lhs);
7435 SCIPintervalSubScalar(SCIPinfinity(scip), &valinterval, valinterval, userow->constant);
7436 SCIPintervalSetRational(&cutarinterval, cutar);
7437 SCIPintervalMul(SCIPinfinity(scip), &valinterval, valinterval, cutarinterval);
7438 SCIPquadprecSumQQ(*cutrhs, *cutrhs, SCIPintervalGetSup(valinterval));
7439 }
7440 }
7441
7442 /* relax rhs to zero, if it's very close to 0 */
7443 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
7444 QUAD_ASSIGN(*cutrhs, 0.0);
7445
7446 if( SCIPisExact(scip) )
7447 SCIPintervalSetRoundingMode(previousroundmode);
7448
7451
7452 SCIPrationalFreeBuffer(SCIPbuffer(scip), &onedivoneminusf0);
7453 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
7454
7455 return SCIP_OKAY;
7456}
7457#endif
7458
7459/** substitute aggregated slack variables:
7460 *
7461 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
7462 * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
7463 *
7464 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
7465 * \f[
7466 * \begin{array}{rll}
7467 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
7468 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
7469 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
7470 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
7471 * \end{array}
7472 * \f]
7473 *
7474 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
7475 */
7476static
7478 SCIP* scip, /**< SCIP data structure */
7479 SCIP_Real* weights, /**< row weights in row summation */
7480 int* slacksign, /**< stores the sign of the row's slack variable in summation */
7481 int* rowinds, /**< sparsity pattern of used rows */
7482 int nrowinds, /**< number of used rows */
7483 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
7484 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7485 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
7486 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7487 int* nnz, /**< number of non-zeros in cut */
7488 QUAD(SCIP_Real f0) /**< fractional value of rhs */
7489 )
7490{ /*lint --e{715}*/
7491 SCIP_ROW** rows;
7492 SCIP_Real QUAD(onedivoneminusf0);
7493 int i;
7494
7495 assert(scip != NULL);
7496 assert(weights != NULL || nrowinds == 0);
7497 assert(slacksign != NULL || nrowinds == 0);
7498 assert(rowinds != NULL || nrowinds == 0);
7499 assert(scale > 0.0);
7500 assert(cutcoefs != NULL);
7501 assert(QUAD_HI(cutrhs) != NULL);
7502 assert(cutinds != NULL);
7503 assert(nnz != NULL);
7504 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
7505 assert(!SCIPisExact(scip));
7506
7507 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
7508 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
7509
7510 rows = SCIPgetLPRows(scip);
7511 for( i = 0; i < nrowinds; i++ )
7512 {
7513 SCIP_ROW* row;
7514 SCIP_Real QUAD(ar);
7515 SCIP_Real QUAD(downar);
7516 SCIP_Real QUAD(cutar);
7517 SCIP_Real QUAD(fr);
7518 SCIP_Real QUAD(tmp);
7519 SCIP_Real QUAD(myprod);
7520 int r;
7521
7522 r = rowinds[i]; /*lint !e613*/
7523 assert(0 <= r && r < SCIPgetNLPRows(scip));
7524 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
7525 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
7526
7527 row = rows[r];
7528 assert(row != NULL);
7529 assert(row->len == 0 || row->cols != NULL);
7530 assert(row->len == 0 || row->cols_index != NULL);
7531 assert(row->len == 0 || row->vals != NULL);
7532
7533 /* get the slack's coefficient a'_r in the aggregated row */
7534 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
7535
7536 /* calculate slack variable's coefficient a^_r in the cut */
7537 if( row->integral )
7538 {
7539 /* slack variable is always integral:
7540 * a^_r = a~_r = down(a'_r) , if f_r <= f0
7541 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
7542 */
7543 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
7544 SCIPquadprecSumQQ(fr, ar, -downar);
7545 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
7546
7547 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
7548 QUAD_ASSIGN_Q(cutar, downar); /* a^_r */
7549 else
7550 {
7551 SCIPquadprecSumQQ(cutar, fr, -f0);
7552 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
7553 SCIPquadprecSumQQ(cutar, cutar, downar);
7554 }
7555 }
7556 else
7557 {
7558 /* slack variable is continuous:
7559 * a^_r = a~_r = 0 , if a'_r >= 0
7560 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
7561 */
7562 if( QUAD_TO_DBL(ar) >= 0.0 )
7563 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
7564 else
7565 SCIPquadprecProdQQ(cutar, onedivoneminusf0, ar);
7566 }
7567
7568 /* if the coefficient was reduced to zero, ignore the slack variable */
7569 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
7570 continue;
7571
7572 /* depending on the slack's sign, we have
7573 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
7574 * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
7575 */
7576 SCIPquadprecProdQD(myprod, cutar, -slacksign[i]);
7577
7578 /* add the slack's definition multiplied with a^_j to the cut */
7579 SCIP_CALL( varVecAddScaledRowCoefsQuadScale(cutinds, cutcoefs, nnz, row, QUAD(myprod)) );
7580
7581 /* move slack's constant to the right hand side */
7582 if( slacksign[i] == +1 ) /*lint !e613*/
7583 {
7584 SCIP_Real QUAD(rowrhs);
7585
7586 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7587 assert(!SCIPisInfinity(scip, row->rhs));
7588 QUAD_ASSIGN(rowrhs, row->rhs - row->constant);
7589 if( row->integral )
7590 {
7591 /* the right hand side was implicitly rounded down in row aggregation */
7592 SCIPquadprecEpsFloorQ(rowrhs, rowrhs, SCIPepsilon(scip)); /*lint !e666*/
7593 }
7594 SCIPquadprecProdQQ(tmp, myprod, rowrhs);
7595 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
7596 }
7597 else
7598 {
7599 SCIP_Real QUAD(rowlhs);
7600
7601 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7602 assert(!SCIPisInfinity(scip, -row->lhs));
7603 QUAD_ASSIGN(rowlhs, row->lhs - row->constant);
7604 if( row->integral )
7605 {
7606 /* the left hand side was implicitly rounded up in row aggregation */
7607 SCIPquadprecEpsCeilQ(rowlhs, rowlhs, SCIPepsilon(scip)); /*lint !e666*/
7608 }
7609 SCIPquadprecProdQQ(tmp, myprod, rowlhs);
7610 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
7611 }
7612 }
7613
7614 /* relax rhs to zero, if it's very close to 0 */
7615 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
7616 QUAD_ASSIGN(*cutrhs, 0.0);
7617
7618 return SCIP_OKAY;
7619}
7620
7621/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
7622 * these rows cannot participate in an MIR cut.
7623 *
7624 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7625 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7626 *
7627 * @pre This method can be called if @p scip is in one of the following stages:
7628 * - \ref SCIP_STAGE_SOLVING
7629 *
7630 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
7631 *
7632 * @note this method is safe for usage in exact solving mode
7633 *
7634 * @todo make behavior identical to the unsafe MIR cut computation
7635 */
7636static
7638 SCIP* scip, /**< SCIP data structure */
7639 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7640 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
7641 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
7642 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
7643 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7644 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
7645 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
7646 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
7647 * NULL for using closest bound for all variables */
7648 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
7649 * NULL for using closest bound for all variables */
7650 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
7651 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
7652 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
7653 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
7654 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
7655 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
7656 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
7657 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
7658 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
7659 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
7660 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
7661 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
7662 )
7663{
7664 int i;
7665 int nvars;
7666 int tmpnnz;
7667 int* varsign;
7668 int* boundtype;
7669 int* tmpinds;
7670 SCIP_Real* tmpcoefs;
7671
7672 SCIP_Real rhs;
7673 SCIP_Real downrhs;
7674 SCIP_Bool freevariable;
7675 SCIP_Bool localbdsused;
7676 SCIP_Bool tmpislocal;
7677
7678 SCIP_ROUNDMODE previousroundmode;
7679 SCIP_INTERVAL f0interval;
7680
7681 assert(aggrrow != NULL);
7682 assert(SCIPisPositive(scip, scale));
7683 assert(SCIPisExact(scip));
7684 assert(success != NULL);
7685
7686 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
7687
7688 *success = FALSE;
7689 *cutislocal = FALSE;
7690
7691 /* allocate temporary memory */
7692 nvars = SCIPgetNVars(scip);
7693 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
7694 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
7695 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
7696 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
7697
7698 /* initialize cut with aggregation */
7699 tmpnnz = aggrrow->nnz;
7700 tmpislocal = aggrrow->local;
7701
7702 previousroundmode = SCIPintervalGetRoundingMode();
7704
7705 if( SCIPisCertified(scip) )
7706 {
7708 }
7709
7710 rhs = QUAD_TO_DBL(aggrrow->rhs) * scale;
7711
7712 if( tmpnnz > 0 )
7713 {
7714 BMScopyMemoryArray(tmpinds, aggrrow->inds, tmpnnz);
7715
7716 for( i = 0; i < tmpnnz; ++i )
7717 {
7718 SCIP_Real coef;
7719 int k = aggrrow->inds[i];
7720
7721 coef = aggrrow->vals[k];
7722 coef *= scale;
7723 tmpcoefs[k] = coef;
7724
7725 assert(coef != 0.0);
7726 }
7727
7728 SCIPdebugMsg(scip, "Initial row:\n");
7729 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
7730
7731 /* Transform equation a*x == b, lb <= x <= ub into standard form
7732 * a'*x' == b, 0 <= x' <= ub'.
7733 *
7734 * Transform variables (lb or ub):
7735 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
7736 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
7737 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
7738 *
7739 * Transform variables (vlb or vub):
7740 * 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.
7741 * 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.
7742 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
7743 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
7744 * a_{zu_j} := a_{zu_j} + a_j * bu_j
7745 */
7746 SCIP_CALL( cutsTransformMIRSafely(scip, sol, boundswitch, usevbds, allowlocal, fixintegralrhs, FALSE,
7747 boundsfortrans, boundtypesfortrans, tmpcoefs, &rhs, tmpinds, &tmpnnz, varsign, boundtype, &freevariable, &localbdsused) );
7748 assert(allowlocal || !localbdsused);
7749 tmpislocal = tmpislocal || localbdsused;
7750
7751 if( freevariable )
7752 goto TERMINATE;
7753
7754 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
7755 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
7756 }
7757
7758 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
7759 * a~*x' <= down(b)
7760 * integers : a~_j = down(a'_j) , if f_j <= f_0
7761 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
7762 * continuous: a~_j = 0 , if a'_j >= 0
7763 * a~_j = a'_j/(1 - f0) , if a'_j < 0
7764 *
7765 * Transform inequality back to a^*x <= rhs:
7766 *
7767 * (lb or ub):
7768 * 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
7769 * 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
7770 * and move the constant terms
7771 * -a~_j * lb_j == -a^_j * lb_j, or
7772 * a~_j * ub_j == -a^_j * ub_j
7773 * to the rhs.
7774 *
7775 * (vlb or vub):
7776 * 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)
7777 * 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)
7778 * move the constant terms
7779 * -a~_j * dl_j == -a^_j * dl_j, or
7780 * a~_j * du_j == -a^_j * du_j
7781 * to the rhs, and update the VB variable coefficients:
7782 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
7783 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
7784 */
7785
7786 downrhs = floor(rhs);
7787
7788 if( SCIPisCertified(scip) )
7789 {
7791 SCIPrationalSetReal(mirinfo->rhs, downrhs);
7792 SCIPrationalSetReal(mirinfo->frac, rhs);
7793 SCIPrationalDiffReal(mirinfo->frac, mirinfo->frac, downrhs);
7794 }
7795
7796 SCIPintervalSet(&f0interval, rhs);
7797 SCIPintervalSubScalar(SCIPinfinity(scip), &f0interval, f0interval, downrhs);
7798
7799 if( f0interval.inf < minfrac || f0interval.sup > maxfrac )
7800 goto TERMINATE;
7801
7802 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
7803 * If this gives a scalar that is very big, we better do not generate this cut.
7804 */
7805 if( REALABS(scale)/(1.0 - f0interval.inf) > MAXCMIRSCALE )
7806 goto TERMINATE;
7807
7808 /* renormalize f0 value */
7809 rhs = downrhs;
7810
7811 if( tmpnnz > 0 )
7812 {
7813 SCIP_CALL( cutsRoundMIRSafely(scip, tmpcoefs, &rhs, tmpinds, &tmpnnz, varsign, boundtype, f0interval) ); /*lint !e644*/
7814
7815 SCIPdebugMsg(scip, "After MIR rounding:\n");
7816 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
7817 }
7818
7819 /* substitute aggregated slack variables:
7820 *
7821 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
7822 * variable only appears in its own row:
7823 * a'_r = scale * weight[r] * slacksign[r].
7824 *
7825 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
7826 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
7827 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
7828 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
7829 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
7830 *
7831 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
7832 */
7833
7834 SCIP_CALL( cutsSubstituteMIRSafely(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
7835 aggrrow->nrows, scale, tmpcoefs, &rhs, tmpinds, &tmpnnz, f0interval) );
7836
7837 SCIPdebugMsg(scip, "After slack substitution:\n");
7838 SCIPdebug( printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE) );
7839
7840 /* we work on rhs -> round up */
7842
7843 if( postprocess )
7844 {
7845 SCIP_CALL( postprocessCutSafely(scip, tmpislocal, tmpinds, tmpcoefs, &tmpnnz, &rhs, success) );
7846 }
7847 else
7848 {
7849 *success = !removeZerosSafely(scip, SCIPsumepsilon(scip), tmpcoefs, &rhs, tmpinds, &tmpnnz);
7850 }
7851
7852 SCIPdebugMsg(scip, "After post processing:\n");
7853 SCIPdebug( printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE) );
7854
7855 if( *success )
7856 {
7857 SCIP_Real mirefficacy = calcEfficacyDenseStorage(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz);
7858
7859 if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
7860 {
7861 BMScopyMemoryArray(cutinds, tmpinds, tmpnnz);
7862 *cutnnz = tmpnnz;
7863 *cutrhs = rhs;
7864 *cutislocal = tmpislocal;
7865
7866 /* clean tmpcoefs and go back to double precision */
7867 for( i = 0; i < *cutnnz; ++i )
7868 {
7869 int j = cutinds[i];
7870
7871 cutcoefs[i] = tmpcoefs[j];
7872 tmpcoefs[j] = 0.0;
7873 }
7874
7875 if( cutefficacy != NULL )
7876 *cutefficacy = mirefficacy;
7877
7878 if( cutrank != NULL )
7879 *cutrank = aggrrow->rank + 1;
7880 }
7881 else
7882 {
7883 *success = FALSE;
7884 }
7885 }
7886
7887 TERMINATE:
7888
7889 /* reset the rounding mode in exact mode */
7890 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
7891
7892 if( !(*success) )
7893 {
7894 for( i = 0; i < tmpnnz; ++i )
7895 {
7896 tmpcoefs[tmpinds[i]] = 0.0;
7897 }
7898 }
7899
7900 /* free temporary memory */
7901 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
7902 SCIPfreeBufferArray(scip, &tmpinds);
7903 SCIPfreeBufferArray(scip, &boundtype);
7904 SCIPfreeBufferArray(scip, &varsign);
7905
7906 return SCIP_OKAY;
7907}
7908
7909
7910/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
7911 * these rows cannot participate in an MIR cut.
7912 *
7913 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7914 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7915 *
7916 * @pre This method can be called if @p scip is in one of the following stages:
7917 * - \ref SCIP_STAGE_SOLVING
7918 *
7919 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
7920 *
7921 * @note this method is safe for usage in exact solving mode
7922 */
7924 SCIP* scip, /**< SCIP data structure */
7925 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7926 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
7927 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
7928 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
7929 * type substitution is allowed. The indices are: 0: continuous,
7930 * 1: continuous implint., 2: integer implint, 3: binary implint,
7931 * 4: integer, 5: binary */
7932 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7933 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
7934 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
7935 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
7936 * NULL for using closest bound for all variables */
7937 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
7938 * NULL for using closest bound for all variables */
7939 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
7940 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
7941 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
7942 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
7943 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
7944 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
7945 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
7946 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
7947 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
7948 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
7949 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
7950 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
7951 )
7952{
7953 MIR_DATA* data;
7954 int* varsign;
7955 int* boundtype;
7956 SCIP_Real QUAD(downrhs);
7957 SCIP_Real QUAD(f0);
7958 SCIP_Bool freevariable;
7959 SCIP_Bool localbdsused;
7960 SCIP_Bool tmpislocal;
7961
7962 assert(aggrrow != NULL);
7963 assert(SCIPisPositive(scip, scale));
7964 assert(success != NULL);
7965
7966 if( SCIPisExact(scip) )
7967 {
7968 /* TODO: update exactSCIP cuts to behave identically with respect to implied integrality */
7969 return calcMIRSafely(scip, sol, postprocess, boundswitch, vartypeusevbds > 0 ? TRUE : FALSE, allowlocal, fixintegralrhs,
7970 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, scale, aggrrow, cutcoefs, cutrhs,
7971 cutinds, cutnnz, cutefficacy, cutrank, cutislocal, success);
7972 }
7973 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
7974
7975 *success = FALSE;
7976
7977 /* Setup data to track cut and initialize the cut with aggregation */
7978 int l;
7979 int nnz;
7980
7981 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
7982
7983 SCIP_CALL( SCIPallocBuffer(scip, &data) );
7984
7985 nnz = aggrrow->nnz;
7986 data->totalnnz = nnz;
7987
7988 /* initialize sections */
7989 for( l = 0; l < NSECTIONS; ++l )
7990 {
7991 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
7992 data->secnnz[l] = 0;
7993 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
7994 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
7995 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
7996 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
7997 /* Use variable bounds for the sections specified by the user */
7998 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
7999 }
8000
8001 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
8002 data->vars = SCIPgetVars(scip);
8003 data->nvars = SCIPgetNVars(scip);
8004 data->nbinvars = SCIPgetNBinVars(scip);
8005 data->nintvars = SCIPgetNIntVars(scip);
8010
8012 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
8013
8014 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, scale);
8015
8016 if( nnz > 0 )
8017 {
8018 /* Initalize cut with the aggregation */
8019 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
8020
8021 for( l = 0; l < nnz; ++l )
8022 {
8023 SCIP_Real QUAD(coef);
8024 int m = aggrrow->inds[l];
8025
8026 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
8027
8028 SCIPquadprecProdQD(coef, coef, scale);
8029
8030 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
8031
8032 assert(QUAD_HI(coef) != 0.0);
8033 }
8034
8035 /* Sort the array by problem index and add the variables to their sections */
8036 SCIPsortDownInt(data->cutinds, nnz);
8037 for( l = 0; l < nnz; ++l )
8038 {
8039 int section = varSection(data, data->cutinds[l]);
8040 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
8041 ++data->secnnz[section];
8042 }
8043 }
8044
8045 SCIPdebugMsg(scip, "Initial row:\n");
8046 SCIPdebug( printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, nnz, FALSE, FALSE) );
8047
8048 data->ncutinds = 0;
8049 tmpislocal = aggrrow->local;
8050
8051 /* allocate temporary memory */
8052 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, data->nvars) );
8053 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, data->nvars) );
8054
8055 /* Transform equation a*x == b, lb <= x <= ub into standard form
8056 * a'*x' == b, 0 <= x' <= ub'.
8057 *
8058 * Transform variables (lb or ub):
8059 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
8060 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
8061 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
8062 *
8063 * Transform variables (vlb or vub):
8064 * 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.
8065 * 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.
8066 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
8067 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
8068 * a_{zu_j} := a_{zu_j} + a_j * bu_j
8069 */
8070 if( data->totalnnz > 0 )
8071 {
8072 SCIP_CALL( cutsTransformMIR(scip, data, sol, boundswitch, allowlocal, fixintegralrhs, FALSE,
8073 boundsfortrans, boundtypesfortrans, minfrac, maxfrac,
8074 varsign, boundtype, &freevariable, &localbdsused) );
8075 assert(allowlocal || !localbdsused);
8076 tmpislocal = tmpislocal || localbdsused;
8077
8078 if( freevariable )
8079 goto TERMINATE;
8080
8081 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
8082 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
8083 }
8084
8085 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
8086 * a~*x' <= down(b)
8087 * integers : a~_j = down(a'_j) , if f_j <= f_0
8088 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
8089 * continuous: a~_j = 0 , if a'_j >= 0
8090 * a~_j = a'_j/(1 - f0) , if a'_j < 0
8091 *
8092 * Transform inequality back to a^*x <= rhs:
8093 *
8094 * (lb or ub):
8095 * 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
8096 * 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
8097 * and move the constant terms
8098 * -a~_j * lb_j == -a^_j * lb_j, or
8099 * a~_j * ub_j == -a^_j * ub_j
8100 * to the rhs.
8101 *
8102 * (vlb or vub):
8103 * 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)
8104 * 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)
8105 * move the constant terms
8106 * -a~_j * dl_j == -a^_j * dl_j, or
8107 * a~_j * du_j == -a^_j * du_j
8108 * to the rhs, and update the VB variable coefficients:
8109 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
8110 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
8111 */
8112
8113 SCIPquadprecEpsFloorQ(downrhs, data->cutrhs, SCIPepsilon(scip)); /*lint !e666*/
8114 SCIPquadprecSumQQ(f0, data->cutrhs, -downrhs);
8115 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
8116
8117 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
8118 goto TERMINATE;
8119
8120 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
8121 * If this gives a scalar that is very big, we better do not generate this cut.
8122 */
8123 if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
8124 goto TERMINATE;
8125
8126 /* renormalize f0 value */
8127 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
8128
8129 QUAD_ASSIGN_Q(data->cutrhs, downrhs);
8130
8131 if( data->totalnnz > 0 )
8132 {
8133 SCIP_CALL( cutsRoundMIR(scip, data, varsign, boundtype, QUAD(f0)) );
8134
8135 SCIPdebugMsg(scip, "After MIR rounding:\n");
8136 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
8137 }
8138
8139 /* substitute aggregated slack variables:
8140 *
8141 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
8142 * variable only appears in its own row:
8143 * a'_r = scale * weight[r] * slacksign[r].
8144 *
8145 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
8146 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
8147 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
8148 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
8149 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
8150 *
8151 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
8152 */
8153 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
8154 aggrrow->nrows, scale,
8155 data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds, QUAD(f0)) );
8156
8157 SCIPdebugMsg(scip, "After slack substitution:\n");
8158 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
8159
8160 if( postprocess )
8161 {
8162 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
8163 * prevent numerical rounding errors
8164 */
8165 SCIP_CALL( postprocessCutQuad(scip, tmpislocal, data->cutinds, data->cutcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
8166 }
8167 else
8168 {
8169 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), tmpislocal, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds);
8170 }
8171
8172 SCIPdebugMsg(scip, "After post processing:\n");
8173 SCIPdebug( printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE) );
8174
8175 if( *success )
8176 {
8177 SCIP_Real mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, data->cutcoefs, QUAD_TO_DBL(data->cutrhs), data->cutinds, data->ncutinds);
8178
8179 if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
8180 {
8181 BMScopyMemoryArray(cutinds, data->cutinds, data->ncutinds);
8182 *cutnnz = data->ncutinds;
8183 *cutrhs = QUAD_TO_DBL(data->cutrhs);
8184 *cutislocal = tmpislocal;
8185
8186 /* clean tmpcoefs and go back to double precision */
8187 for(int i = 0; i < *cutnnz; ++i )
8188 {
8189 SCIP_Real QUAD(coef);
8190 int j = cutinds[i];
8191
8192 QUAD_ARRAY_LOAD(coef, data->cutcoefs, j);
8193
8194 cutcoefs[i] = QUAD_TO_DBL(coef);
8195 QUAD_ASSIGN(coef, 0.0);
8196 QUAD_ARRAY_STORE(data->cutcoefs, j, coef);
8197 }
8198
8199 if( cutefficacy != NULL )
8200 *cutefficacy = mirefficacy;
8201
8202 if( cutrank != NULL )
8203 *cutrank = aggrrow->rank + 1;
8204 }
8205 else
8206 {
8207 *success = FALSE;
8208 }
8209 }
8210
8211 TERMINATE:
8212 if( !(*success) )
8213 {
8214 SCIP_Real QUAD(tmp);
8215
8216 QUAD_ASSIGN(tmp, 0.0);
8217 for(int i = 0; i < data->ncutinds; ++i )
8218 {
8219 QUAD_ARRAY_STORE(data->cutcoefs, data->cutinds[i], tmp);
8220 }
8221 }
8222
8223#ifndef NDEBUG
8224 for( int i = 0; i < QUAD_ARRAY_SIZE(data->nvars); ++i )
8225 {
8226 if(data->cutcoefs[i] != 0.0)
8227 {
8228 SCIPdebugMsg(scip, "coefs have not been reset\n");
8229 SCIPABORT();
8230 }
8231 }
8232#endif
8233
8234 SCIPfreeBufferArray(scip, &boundtype);
8235 SCIPfreeBufferArray(scip, &varsign);
8236
8237 if( data->cutinds != NULL )
8239
8240 if( data->cutcoefs != NULL )
8242
8243 for( int s = NSECTIONS - 1; s >= 0; --s )
8244 {
8246 }
8247
8248 SCIPfreeBuffer(scip, &data);
8249
8250 return SCIP_OKAY;
8251}
8252
8253/** compute the efficacy of the MIR cut for the given values without computing the cut.
8254 * This is used for the CMIR cut generation heuristic.
8255 */
8256static
8258 SCIP* scip, /**< SCIP datastructure */
8259 SCIP_Real*RESTRICT coefs, /**< array with coefficients in row */
8260 SCIP_Real*RESTRICT solvals, /**< solution values of variables in the row */
8261 SCIP_Real rhs, /**< right hand side of MIR cut */
8262 SCIP_Real contactivity, /**< aggregated activity of continuous variables in the row */
8263 SCIP_Real contsqrnorm, /**< squared norm of continuous variables */
8264 SCIP_Real delta, /**< delta value to compute the violation for */
8265 int nvars, /**< number of variables in the row, i.e. the size of coefs and solvals arrays */
8266 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
8267 SCIP_Real maxfrac /**< maximal fractionality of rhs to produce MIR cut for */
8268 )
8269{
8270 int i;
8271 SCIP_Real f0pluseps;
8272 SCIP_Real f0;
8273 SCIP_Real onedivoneminusf0;
8274 SCIP_Real scale;
8275 SCIP_Real downrhs;
8276 SCIP_Real norm;
8277 SCIP_Real contscale;
8278
8279 scale = 1.0 / delta;
8280 rhs *= scale;
8281 downrhs = SCIPfloor(scip, rhs);
8282 f0 = rhs - downrhs;
8283
8284 if( f0 < minfrac || f0 > maxfrac )
8285 return 0.0;
8286
8287 onedivoneminusf0 = 1.0 / (1.0 - f0);
8288
8289 contscale = scale * onedivoneminusf0;
8290
8291 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
8292 * If this gives a scalar that is very big, we better do not generate this cut.
8293 */
8294 if( contscale > MAXCMIRSCALE )
8295 return 0.0;
8296
8297 rhs = downrhs;
8298 rhs -= contscale * contactivity;
8299 norm = SQR(contscale) * contsqrnorm;
8300
8301 assert(!SCIPisFeasZero(scip, f0));
8302 assert(!SCIPisFeasZero(scip, 1.0 - f0));
8303
8304 f0pluseps = f0 + SCIPepsilon(scip);
8305
8306 for( i = 0; i < nvars; ++i )
8307 {
8308 SCIP_Real floorai = SCIPfloor(scip, scale * coefs[i]);
8309 SCIP_Real fi = (scale * coefs[i]) - floorai;
8310
8311 if( fi > f0pluseps )
8312 floorai += (fi - f0) * onedivoneminusf0;
8313
8314 rhs -= solvals[i] * floorai;
8315 norm += SQR(floorai);
8316 }
8317
8318 norm = sqrt(norm);
8319
8320 return - rhs / MAX(norm, 1e-6);
8321}
8322
8323/** calculates an MIR cut out of an aggregation of LP rows
8324 *
8325 * Given the aggregation, it is transformed to a mixed knapsack set via complementation (using bounds or variable bounds)
8326 * Then, different scalings of the mkset are used to generate a MIR and the best is chosen.
8327 * One of the steps of the MIR is to round the coefficients of the integer variables down,
8328 * so one would prefer to have integer coefficients for integer variables which are far away from their bounds in the
8329 * mkset.
8330 *
8331 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8332 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8333 *
8334 * @pre This method can be called if @p scip is in one of the following stages:
8335 * - \ref SCIP_STAGE_SOLVING
8336 *
8337 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
8338 */
8340 SCIP* scip, /**< SCIP data structure */
8341 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8342 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
8343 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
8344 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
8345 * type substitution is allowed. The indices are: 0: continuous,
8346 * 1: continuous implint., 2: integer implint, 3: binary implint,
8347 * 4: integer, 5: binary */
8348 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8349 int maxtestdelta, /**< maximum number of deltas to test */
8350 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
8351 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
8352 * NULL for using closest bound for all variables */
8353 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
8354 * NULL for using closest bound for all variables */
8355 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
8356 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
8357 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
8358 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
8359 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
8360 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
8361 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
8362 SCIP_Real* cutefficacy, /**< pointer to store efficacy of best cut; only cuts that are strictly better than the value of
8363 * this efficacy on input to this function are returned */
8364 int* cutrank, /**< pointer to return rank of generated cut (or NULL) */
8365 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
8366 SCIP_Bool* success /**< pointer to store whether a valid and efficacious cut was returned */
8367 )
8368{
8369 int i;
8370 int firstcontvar;
8371 int nvars;
8372 int intstart;
8373 int ntmpcoefs;
8374 int* varsign;
8375 int* boundtype;
8376 int* mksetinds;
8377 SCIP_Real* mksetcoefs;
8378 SCIP_Real QUAD(mksetrhs);
8379 int mksetnnz;
8380 SCIP_Real* bounddist;
8381 int* bounddistpos;
8382 int nbounddist;
8383 SCIP_Real* tmpcoefs;
8384 SCIP_Real* tmpvalues;
8385 SCIP_Real* deltacands;
8386 int ndeltacands;
8387 SCIP_Real bestdelta;
8388 SCIP_Real bestefficacy;
8389 SCIP_Real maxabsmksetcoef;
8390 SCIP_VAR** vars;
8391 SCIP_Bool freevariable;
8392 SCIP_Bool localbdsused;
8393 SCIP_Real contactivity;
8394 SCIP_Real contsqrnorm;
8395 MIR_DATA* data;
8396
8397 assert(aggrrow != NULL);
8398 assert(aggrrow->nrows + aggrrow->nnz >= 1);
8399 assert(success != NULL);
8400
8401 *success = FALSE;
8402 nvars = SCIPgetNVars(scip);
8403 firstcontvar = nvars - SCIPgetNContVars(scip) - SCIPgetNContImplVars(scip);
8404 vars = SCIPgetVars(scip);
8405
8406 /* allocate temporary memory */
8407 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
8408 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
8409
8410 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, nvars + aggrrow->nrows) );
8411 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars + aggrrow->nrows) );
8412 /* The +4 comes from a few rules that create extra delta candidates, see usages of ndeltacands. */
8413 SCIP_CALL( SCIPallocBufferArray(scip, &deltacands, nvars + 4) );
8414
8415 /* we only compute bound distance for integer variables; by variable bound substitution, the number of integer variables
8416 * can grow significantly. Hence, these allocations are length nvars */
8417 SCIP_CALL( SCIPallocBufferArray(scip, &bounddist, nvars) );
8418 SCIP_CALL( SCIPallocBufferArray(scip, &bounddistpos, nvars) );
8419
8420 /* initialize mkset with the unscaled aggregation */
8421 {
8422 int l;
8423 int nnz;
8424
8425 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
8426
8427 SCIP_CALL( SCIPallocBuffer(scip, &data) );
8428
8429 nnz = aggrrow->nnz;
8430 data->totalnnz = nnz;
8431
8432 /* initialize sections */
8433 for( l = 0; l < NSECTIONS; ++l )
8434 {
8435 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
8436 data->secnnz[l] = 0;
8437 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
8438 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
8439 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
8440 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
8441 /* Use variable bounds for the sections specified by the user */
8442 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
8443 }
8444
8445 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
8446 data->vars = SCIPgetVars(scip);
8447 data->nvars = SCIPgetNVars(scip);
8448 data->nbinvars = SCIPgetNBinVars(scip);
8449 data->nintvars = SCIPgetNIntVars(scip);
8454
8456 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
8457
8458 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, 1.0);
8459
8460 if( nnz > 0 )
8461 {
8462 /* Initalize cut with the aggregation */
8463 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
8464
8465 for( l = 0; l < nnz; ++l )
8466 {
8467 SCIP_Real QUAD(coef);
8468 int m = aggrrow->inds[l];
8469
8470 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
8471
8472 SCIPquadprecProdQD(coef, coef, 1.0);
8473
8474 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
8475
8476 assert(QUAD_HI(coef) != 0.0);
8477 }
8478
8479 /* Sort the array by problem index and add the variables to their sections */
8480 SCIPsortDownInt(data->cutinds, nnz);
8481 for( l = 0; l < nnz; ++l )
8482 {
8483 int section = varSection(data, data->cutinds[l]);
8484 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
8485 ++data->secnnz[section];
8486 }
8487 }
8488
8489 data->ncutinds = 0;
8490 }
8491 *cutislocal = aggrrow->local;
8492
8493 /* Transform equation a*x == b, lb <= x <= ub into standard form
8494 * a'*x' == b, 0 <= x' <= ub'.
8495 *
8496 * Transform variables (lb or ub):
8497 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
8498 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
8499 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
8500 *
8501 * Transform variables (vlb or vub):
8502 * 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.
8503 * 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.
8504 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
8505 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
8506 * a_{zu_j} := a_{zu_j} + a_j * bu_j
8507 */
8508 SCIP_CALL( cutsTransformMIR(scip, data, sol, boundswitch, allowlocal, FALSE, FALSE,
8509 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, varsign, boundtype, &freevariable, &localbdsused) );
8510 assert(allowlocal || !localbdsused);
8511
8512 /* Use aliases to stay more consistent with the old code. mksetrhs needs to synchronize its values data->cutrhs
8513 * again before calling SCIProundMIR()! */
8514 mksetinds = data->cutinds;
8515 mksetcoefs = data->cutcoefs;
8516 mksetnnz = data->ncutinds;
8517 QUAD_ASSIGN_Q(mksetrhs, data->cutrhs);
8518
8519 if( freevariable )
8520 goto TERMINATE;
8521
8522 SCIPdebugMsg(scip, "transformed aggrrow row:\n");
8523 SCIPdebug( printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE) );
8524
8525 /* found positions of integral variables that are strictly between their bounds */
8526 maxabsmksetcoef = -1.0;
8527 nbounddist = 0;
8528
8529 assert(mksetnnz <= nvars);
8530 for( i = mksetnnz - 1; i >= 0 && mksetinds[i] < firstcontvar; --i )
8531 {
8532 SCIP_VAR* var = vars[mksetinds[i]];
8533 SCIP_Real primsol = SCIPgetSolVal(scip, sol, var);
8534 SCIP_Real lb = SCIPvarGetLbLocal(var);
8535 SCIP_Real ub = SCIPvarGetUbLocal(var);
8536 SCIP_Real QUAD(coef);
8537
8538 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
8539
8540 if( SCIPisEQ(scip, primsol, lb) || SCIPisEQ(scip, primsol, ub) )
8541 continue;
8542
8543 bounddist[nbounddist] = MIN(ub - primsol, primsol - lb);
8544 bounddistpos[nbounddist] = i;
8545 deltacands[nbounddist] = QUAD_TO_DBL(coef);
8546 ++nbounddist;
8547 }
8548 assert(nbounddist <= nvars);
8549
8550 /* no fractional variable; so abort here */
8551 if( nbounddist == 0 )
8552 goto TERMINATE;
8553
8554 intstart = i + 1;
8555
8556 /* Check that the continuous and implied integer variables and integer variables are partitioned */
8557#ifndef NDEBUG
8558 for( int j = 0; j < intstart; ++j )
8559 {
8560 assert(SCIPvarGetType(vars[mksetinds[j]]) == SCIP_VARTYPE_CONTINUOUS);
8561 }
8562 for( int j = intstart; j < data->ncutinds; ++j )
8563 {
8564 assert(SCIPvarIsIntegral(vars[mksetinds[j]]));
8565 }
8566#endif
8567
8568 ndeltacands = nbounddist;
8569 assert(ndeltacands <= nvars);
8570 SCIPsortDownRealRealInt(bounddist, deltacands, bounddistpos, nbounddist);
8571
8572 {
8573 SCIP_Real intscale;
8574 SCIP_Bool intscalesuccess;
8575
8576 SCIP_CALL( SCIPcalcIntegralScalar(deltacands, nbounddist, -SCIPepsilon(scip), SCIPsumepsilon(scip), (SCIP_Longint)10000, 10000.0, &intscale, &intscalesuccess) );
8577
8578 if( intscalesuccess )
8579 {
8580 SCIP_Real intf0;
8581 SCIP_Real intscalerhs;
8582 SCIP_Real delta;
8583
8584 intscalerhs = QUAD_TO_DBL(data->cutrhs) * intscale;
8585 delta = 1.0 / intscale;
8586 intf0 = intscalerhs - floor(intscalerhs);
8587
8588 if( ! SCIPisFeasIntegral(scip, intf0) )
8589 {
8590 if( intf0 < minfrac || intf0 > maxfrac )
8591 {
8592 intscale *= SCIPceil(scip, MAX(minfrac, (1.0 - maxfrac)) / MIN(intf0, (1.0 - intf0)));
8593 intscalerhs = QUAD_TO_DBL(data->cutrhs) * intscale;
8594 delta = 1.0 / intscale;
8595 intf0 = intscalerhs - floor(intscalerhs);
8596 }
8597
8598 if( intf0 >= minfrac && intf0 <= maxfrac )
8599 {
8600 if( ! SCIPisEQ(scip, delta, 1.0) )
8601 deltacands[ndeltacands++] = delta;
8602
8603 if( intf0 < maxfrac )
8604 {
8605 SCIP_Real delta2;
8606
8607 delta2 = 1.0 / (intscale * SCIPfloor(scip, maxfrac / intf0));
8608
8609 if( ! SCIPisEQ(scip, delta, delta2) && ! SCIPisEQ(scip, delta2, 1.0) )
8610 deltacands[ndeltacands++] = delta2;
8611 }
8612 }
8613 }
8614 }
8615 }
8616
8617 for( i = 0; i < nbounddist; ++i )
8618 {
8619 SCIP_Real absmksetcoef;
8620
8621 absmksetcoef = REALABS(deltacands[i]);
8622 maxabsmksetcoef = MAX(absmksetcoef, maxabsmksetcoef);
8623
8624 deltacands[i] = absmksetcoef;
8625 }
8626
8627 /* also test 1.0 and maxabsmksetcoef + 1.0 as last delta values */
8628 if( maxabsmksetcoef != -1.0 )
8629 deltacands[ndeltacands++] = maxabsmksetcoef + 1.0;
8630
8631 deltacands[ndeltacands++] = 1.0;
8632
8633 maxtestdelta = MIN(ndeltacands, maxtestdelta);
8634
8635 /* For each delta
8636 * Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
8637 * a~*x' <= down(b)
8638 * integers : a~_j = down(a'_j) , if f_j <= f_0
8639 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
8640 * continuous: a~_j = 0 , if a'_j >= 0
8641 * a~_j = a'_j/(1 - f0) , if a'_j < 0
8642 *
8643 * Transform inequality back to a^*x <= rhs:
8644 *
8645 * (lb or ub):
8646 * 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
8647 * 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
8648 * and move the constant terms
8649 * -a~_j * lb_j == -a^_j * lb_j, or
8650 * a~_j * ub_j == -a^_j * ub_j
8651 * to the rhs.
8652 *
8653 * (vlb or vub):
8654 * 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)
8655 * 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)
8656 * move the constant terms
8657 * -a~_j * dl_j == -a^_j * dl_j, or
8658 * a~_j * du_j == -a^_j * du_j
8659 * to the rhs, and update the VB variable coefficients:
8660 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
8661 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
8662 */
8663
8664 ntmpcoefs = 0;
8665 assert(mksetnnz <= nvars);
8666 for( i = intstart; i < mksetnnz; ++i )
8667 {
8668 SCIP_VAR* var;
8669 SCIP_Real solval;
8670 SCIP_Real QUAD(coef);
8671
8672 var = vars[mksetinds[i]];
8673
8674 /* get the soltion value of the continuous variable */
8675 solval = SCIPgetSolVal(scip, sol, var);
8676
8677 /* now compute the solution value in the transform space considering complementation */
8678 if( boundtype[i] == -1 )
8679 {
8680 /* variable was complemented with global (simple) bound */
8681 if( varsign[i] == -1 )
8682 solval = SCIPvarGetUbGlobal(var) - solval;
8683 else
8684 solval = solval - SCIPvarGetLbGlobal(var);
8685 }
8686 else
8687 {
8688 assert(boundtype[i] == -2);
8689
8690 /* variable was complemented with local (simple) bound */
8691 if( varsign[i] == -1 )
8692 solval = SCIPvarGetUbLocal(var) - solval;
8693 else
8694 solval = solval - SCIPvarGetLbLocal(var);
8695 }
8696
8697 tmpvalues[ntmpcoefs] = solval;
8698 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
8699 tmpcoefs[ntmpcoefs] = varsign[i] * QUAD_TO_DBL(coef);
8700 ++ntmpcoefs;
8701 }
8702
8703 assert(ntmpcoefs == mksetnnz - intstart);
8704
8705 contactivity = 0.0;
8706 contsqrnorm = 0.0;
8707 for( i = 0; i < intstart; ++i )
8708 {
8709 SCIP_Real solval;
8710 SCIP_Real QUAD(mksetcoef);
8711
8712 QUAD_ARRAY_LOAD(mksetcoef, mksetcoefs, mksetinds[i]);
8713
8714 if( varsign[i] * QUAD_TO_DBL(mksetcoef) >= 0.0 )
8715 continue;
8716
8717 /* get the soltion value of the continuous variable */
8718 solval = SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
8719
8720 /* now compute the solution value in the transform space considering complementation */
8721 switch( boundtype[i] )
8722 {
8723 case -1:
8724 /* variable was complemented with global (simple) bound */
8725 if( varsign[i] == -1 )
8726 solval = SCIPvarGetUbGlobal(vars[mksetinds[i]]) - solval;
8727 else
8728 solval = solval - SCIPvarGetLbGlobal(vars[mksetinds[i]]);
8729 break;
8730 case -2:
8731 /* variable was complemented with local (simple) bound */
8732 if( varsign[i] == -1 )
8733 solval = SCIPvarGetUbLocal(vars[mksetinds[i]]) - solval;
8734 else
8735 solval = solval - SCIPvarGetLbLocal(vars[mksetinds[i]]);
8736 break;
8737 default:
8738 /* variable was complemented with a variable bound */
8739 if( varsign[i] == -1 )
8740 {
8741 SCIP_Real coef;
8742 SCIP_Real constant;
8743 SCIP_Real vbdsolval;
8744
8745 coef = SCIPvarGetVubCoefs(vars[mksetinds[i]])[boundtype[i]];
8746 constant = SCIPvarGetVubConstants(vars[mksetinds[i]])[boundtype[i]];
8747 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVubVars(vars[mksetinds[i]])[boundtype[i]]);
8748
8749 solval = (coef * vbdsolval + constant) - solval;
8750 }
8751 else
8752 {
8753 SCIP_Real coef;
8754 SCIP_Real constant;
8755 SCIP_Real vbdsolval;
8756
8757 coef = SCIPvarGetVlbCoefs(vars[mksetinds[i]])[boundtype[i]];
8758 constant = SCIPvarGetVlbConstants(vars[mksetinds[i]])[boundtype[i]];
8759 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVlbVars(vars[mksetinds[i]])[boundtype[i]]);
8760
8761 solval = solval - (coef * vbdsolval + constant);
8762 }
8763 }
8764
8765 contactivity += solval * (QUAD_TO_DBL(mksetcoef) * varsign[i]);
8766 contsqrnorm += QUAD_TO_DBL(mksetcoef) * QUAD_TO_DBL(mksetcoef);
8767 }
8768
8769 {
8770 SCIP_ROW** rows;
8771
8772 rows = SCIPgetLPRows(scip);
8773 assert(ntmpcoefs <= nvars);
8774 for( i = 0; i < aggrrow->nrows; ++i )
8775 {
8776 SCIP_ROW* row;
8777 SCIP_Real slackval;
8778
8779 row = rows[aggrrow->rowsinds[i]];
8780
8781 if( (aggrrow->rowweights[i] * aggrrow->slacksign[i]) >= 0.0 && !row->integral )
8782 continue;
8783
8784 /* compute solution value of slack variable */
8785 slackval = SCIPgetRowSolActivity(scip, row, sol);
8786
8787 if( aggrrow->slacksign[i] == +1 )
8788 {
8789 /* right hand side */
8790 assert(!SCIPisInfinity(scip, row->rhs));
8791
8792 slackval = row->rhs - slackval;
8793 }
8794 else
8795 {
8796 /* left hand side */
8797 assert(aggrrow->slacksign[i] == -1);
8798 assert(!SCIPisInfinity(scip, -row->lhs));
8799
8800 slackval = slackval - row->lhs;
8801 }
8802
8803 if( row->integral )
8804 {
8805 /* if row is integral add variable to tmp arrays */
8806 tmpvalues[ntmpcoefs] = slackval;
8807 tmpcoefs[ntmpcoefs] = aggrrow->rowweights[i] * aggrrow->slacksign[i];
8808 ++ntmpcoefs;
8809 }
8810 else
8811 {
8812 SCIP_Real slackcoeff = (aggrrow->rowweights[i] * aggrrow->slacksign[i]);
8813
8814 /* otherwise add it to continuous activity */
8815 contactivity += slackval * slackcoeff;
8816 contsqrnorm += SQR(slackcoeff);
8817 }
8818 }
8819 }
8820
8821 /* try all candidates for delta and remember best */
8822 bestdelta = SCIP_INVALID;
8823 bestefficacy = -SCIPinfinity(scip);
8824
8825 for( i = 0; i < maxtestdelta; ++i )
8826 {
8827 int j;
8828 SCIP_Real efficacy;
8829
8830 /* check if we have seen this value of delta before */
8831 SCIP_Bool deltaseenbefore = FALSE;
8832 for( j = 0; j < i; ++j )
8833 {
8834 if( SCIPisEQ(scip, deltacands[i], deltacands[j]) )
8835 {
8836 deltaseenbefore = TRUE;
8837 break;
8838 }
8839 }
8840
8841 /* skip this delta value and allow one more delta value if available */
8842 if( deltaseenbefore )
8843 {
8844 maxtestdelta = MIN(maxtestdelta + 1, ndeltacands);
8845 continue;
8846 }
8847
8848 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, deltacands[i], ntmpcoefs, minfrac, maxfrac);
8849
8850 if( efficacy > bestefficacy )
8851 {
8852 bestefficacy = efficacy;
8853 bestdelta = deltacands[i];
8854 }
8855 }
8856
8857 /* no delta was found that yielded any cut */
8858 if( bestdelta == SCIP_INVALID ) /*lint !e777*/
8859 goto TERMINATE;
8860
8861 /* try bestdelta divided by 2, 4 and 8 */
8862 {
8863 SCIP_Real basedelta = bestdelta;
8864 for( i = 2; i <= 8 ; i *= 2 )
8865 {
8866 SCIP_Real efficacy;
8867 SCIP_Real delta;
8868
8869 delta = basedelta / i;
8870
8871 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, delta, ntmpcoefs, minfrac, maxfrac);
8872
8873 if( efficacy > bestefficacy )
8874 {
8875 bestefficacy = efficacy;
8876 bestdelta = delta;
8877 }
8878 }
8879 }
8880
8881 /* try to improve efficacy by switching complementation of integral variables that are not at their bounds
8882 * in order of non-increasing bound distance
8883 */
8884 for( i = 0; i < nbounddist; ++i )
8885 {
8886 int k;
8887 SCIP_Real newefficacy;
8888 SCIP_Real QUAD(newrhs);
8889 SCIP_Real QUAD(quadprod);
8890 SCIP_Real bestlb;
8891 SCIP_Real bestub;
8892 SCIP_Real oldsolval;
8893 int bestlbtype;
8894 int bestubtype;
8895
8896 k = bounddistpos[i];
8897
8898 SCIP_CALL( findBestLb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestlb, &bestlbtype) );
8899
8900 if( SCIPisInfinity(scip, -bestlb) )
8901 continue;
8902
8903 SCIP_CALL( findBestUb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestub, &bestubtype) );
8904
8905 if( SCIPisInfinity(scip, bestub) )
8906 continue;
8907
8908 /* switch the complementation of this variable */
8909#ifndef NDEBUG
8910 {
8911 SCIP_Real QUAD(coef);
8912 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[k]);
8913 assert(SCIPisEQ(scip, tmpcoefs[k - intstart], varsign[k] * QUAD_TO_DBL(coef)));
8914 }
8915#endif
8916
8917 /* compute this: newrhs = mksetrhs + tmpcoefs[k - intstart] * (bestlb - bestub); */
8918 SCIPquadprecProdDD(quadprod, tmpcoefs[k - intstart], bestlb - bestub);
8919 SCIPquadprecSumQQ(newrhs, mksetrhs, quadprod);
8920 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
8921
8922 oldsolval = tmpvalues[k - intstart];
8923 tmpvalues[k - intstart] = varsign[k] == +1 ? bestub - SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) : SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) - bestlb;
8924
8925 /* compute new violation */
8926 newefficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(newrhs), contactivity, contsqrnorm, bestdelta, ntmpcoefs, minfrac, maxfrac);
8927
8928 /* check if violation was increased */
8929 if( newefficacy > bestefficacy )
8930 {
8931 /* keep change of complementation */
8932 bestefficacy = newefficacy;
8933 QUAD_ASSIGN_Q(mksetrhs, newrhs);
8934
8935 if( varsign[k] == +1 )
8936 {
8937 /* switch to upper bound */
8938 assert(bestubtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
8939 boundtype[k] = bestubtype;
8940 varsign[k] = -1;
8941 }
8942 else
8943 {
8944 /* switch to lower bound */
8945 assert(bestlbtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
8946 boundtype[k] = bestlbtype;
8947 varsign[k] = +1;
8948 }
8949
8950 localbdsused = localbdsused || (boundtype[k] == -2);
8951 }
8952 else
8953 {
8954 /* undo the change of the complementation */
8955 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
8956 tmpvalues[k - intstart] = oldsolval;
8957 }
8958 } /*lint !e438*/
8959
8960 if( bestefficacy > 0.0 )
8961 {
8962 SCIP_Real mirefficacy;
8963 SCIP_Real QUAD(downrhs);
8964 SCIP_Real QUAD(f0);
8965 SCIP_Real scale;
8966
8967 scale = 1.0 / bestdelta;
8968 SCIPquadprecProdQD(mksetrhs, mksetrhs, scale);
8969 SCIPquadprecEpsFloorQ(downrhs, mksetrhs, SCIPepsilon(scip)); /*lint !e666*/
8970 SCIPquadprecSumQQ(f0, mksetrhs, -downrhs);
8971 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
8972
8973 /* renormalize f0 value */
8974 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
8975
8976 /* scale entries by the chosen scale factor */
8977 for( i = 0; i < mksetnnz; ++i )
8978 {
8979 SCIP_Real QUAD(coef);
8980
8981 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
8982 SCIPquadprecProdQD(coef, coef, scale);
8983 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], coef);
8984 }
8985 SCIPdebugMsg(scip, "applied best scale (=%.13g):\n", scale);
8986 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
8987
8988 QUAD_ASSIGN_Q(mksetrhs, downrhs);
8989
8990 QUAD_ASSIGN_Q(data->cutrhs, mksetrhs);
8991
8992 SCIP_CALL( cutsRoundMIR(scip, data, varsign, boundtype, QUAD(f0)) );
8993
8994 SCIPdebugMsg(scip, "rounded MIR cut:\n");
8995 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
8996
8997 /* substitute aggregated slack variables:
8998 *
8999 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
9000 * variable only appears in its own row:
9001 * a'_r = scale * weight[r] * slacksign[r].
9002 *
9003 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
9004 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
9005 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
9006 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
9007 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
9008 *
9009 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
9010 */
9011 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
9012 aggrrow->nrows, scale, mksetcoefs, QUAD(&data->cutrhs), mksetinds, &data->ncutinds, QUAD(f0)) );
9013
9014 SCIPdebugMsg(scip, "substituted slacks in MIR cut:\n");
9015 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
9016
9017#ifndef NDEBUG
9018 {
9019 SCIP_Real efficacy = -QUAD_TO_DBL(data->cutrhs);
9020 for( i = 0; i < data->ncutinds; ++i )
9021 {
9022 SCIP_Real QUAD(coef);
9023 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
9024 efficacy += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
9025 }
9026
9027 if( !EPSZ(SCIPrelDiff(efficacy, bestefficacy), 1e-4) )
9028 {
9029 SCIPdebugMsg(scip, "efficacy of cmir cut is different than expected efficacy: %f != %f\n", efficacy, bestefficacy);
9030 }
9031 }
9032#endif
9033
9034 *cutislocal = *cutislocal || localbdsused;
9035
9036 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
9037 * prevent numerical rounding errors
9038 */
9039 if( postprocess )
9040 {
9041 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, mksetinds, mksetcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
9042 }
9043 else
9044 {
9045 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, mksetcoefs, QUAD(&data->cutrhs), mksetinds, &data->ncutinds);
9046 }
9047
9048 SCIPdebugMsg(scip, "post-processed cut (success = %s):\n", *success ? "TRUE" : "FALSE");
9049 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
9050
9051 if( *success )
9052 {
9053 mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, mksetcoefs, QUAD_TO_DBL(data->cutrhs), mksetinds, data->ncutinds);
9054
9055 if( SCIPisEfficacious(scip, mirefficacy) && SCIPisGT(scip, mirefficacy, *cutefficacy) )
9056 {
9057 BMScopyMemoryArray(cutinds, mksetinds, data->ncutinds);
9058 for( i = 0; i < data->ncutinds; ++i )
9059 {
9060 SCIP_Real QUAD(coef);
9061 int j = cutinds[i];
9062
9063 QUAD_ARRAY_LOAD(coef, mksetcoefs, j);
9064
9065 cutcoefs[i] = QUAD_TO_DBL(coef);
9066 QUAD_ASSIGN(coef, 0.0);
9067 QUAD_ARRAY_STORE(mksetcoefs, j, coef);
9068 }
9069 *cutnnz = data->ncutinds;
9070 *cutrhs = QUAD_TO_DBL(data->cutrhs);
9071 *cutefficacy = mirefficacy;
9072 if( cutrank != NULL )
9073 *cutrank = aggrrow->rank + 1;
9074 *cutislocal = *cutislocal || localbdsused;
9075 }
9076 else
9077 *success = FALSE;
9078 }
9079 }
9080
9081 TERMINATE:
9082 /* if we aborted early we need to clean the mksetcoefs */
9083 if( !(*success) )
9084 {
9085 SCIP_Real QUAD(tmp);
9086 QUAD_ASSIGN(tmp, 0.0);
9087
9088 for( i = 0; i < data->ncutinds; ++i )
9089 {
9090 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], tmp);
9091 }
9092 }
9093
9094#ifndef NDEBUG
9095 for( i = 0; i < QUAD_ARRAY_SIZE(nvars); ++i )
9096 {
9097 if(mksetcoefs[i] != 0.0)
9098 {
9099 SCIPdebugMsg(scip, "mksetcoefs have not been reset\n");
9100 SCIPABORT();
9101 }
9102 }
9103#endif
9104
9105 if( data->cutinds != NULL )
9107
9108 if( data->cutcoefs != NULL )
9110
9111 for( int s = NSECTIONS - 1; s >= 0; --s )
9112 {
9114 }
9115
9116 SCIPfreeBuffer(scip, &data);
9117 /* free temporary memory */
9118 SCIPfreeBufferArray(scip, &bounddistpos);
9119 SCIPfreeBufferArray(scip, &bounddist);
9120 SCIPfreeBufferArray(scip, &deltacands);
9121 SCIPfreeBufferArray(scip, &tmpvalues);
9122 SCIPfreeBufferArray(scip, &tmpcoefs);
9123 SCIPfreeBufferArray(scip, &boundtype);
9124 SCIPfreeBufferArray(scip, &varsign);
9125
9126 return SCIP_OKAY;
9127}
9128
9129/* =========================================== flow cover =========================================== */
9130
9131#define NO_EXACT_KNAPSACK
9132
9133#ifndef NO_EXACT_KNAPSACK
9134#define MAXDNOM 1000LL
9135#define MINDELTA 1e-03
9136#define MAXDELTA 1e-09
9137#define MAXSCALE 1000.0
9138#define MAXDYNPROGSPACE 1000000
9139#endif
9140
9141#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for snf relaxation */
9142#define MAXBOUND 1e+10 /**< maximal value of normal bounds used for snf relaxation */
9143
9144/** structure that contains all data required to perform the sequence independent lifting
9145 */
9146typedef
9147struct LiftingData
9148{
9149 SCIP_Real* M; /**< \f$ M_0 := 0.0 \f$ and \f$ M_i := M_i-1 + m_i \f$ */
9150 SCIP_Real* m; /**< non-increasing array of variable upper bound coefficients
9151 * for all variables in \f$ C^{++} \f$ and \f$ L^- \f$,
9152 * where \f$ C = C^+ \cup C^- \f$ is the flowcover and
9153 * \f$ C^{++} := \{ j \in C^+ \mid u_j > \lambda \} \f$
9154 * \f$ L^- := \{ j \in (N^- \setminus C^-) \mid u_j > \lambda \} \f$
9155 */
9156 int r; /**< size of array m */
9157 int t; /**< index of smallest value in m that comes from a variable in \f$ C^{++} \f$ */
9158 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$ */
9159 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$ */
9160 SCIP_Real lambda; /**< excess of the flowcover */
9161 SCIP_Real mp; /**< smallest variable bound coefficient of variable in \f$ C^{++} (min_{j \in C++} u_j) \f$ */
9162 SCIP_Real ml; /**< \f$ ml := min(\lambda, \sum_{j \in C^+ \setminus C^{++}} u_j) \f$ */
9164
9165/** structure that contains all the data that defines the single-node-flow relaxation of an aggregation row */
9166typedef
9167struct SNF_Relaxation
9168{
9169 int* transvarcoefs; /**< coefficients of all vars in relaxed set */
9170 SCIP_Real* transbinvarsolvals; /**< sol val of bin var in vub of all vars in relaxed set */
9171 SCIP_Real* transcontvarsolvals;/**< sol val of all real vars in relaxed set */
9172 SCIP_Real* transvarvubcoefs; /**< coefficient in vub of all vars in relaxed set */
9173 int ntransvars; /**< number of vars in relaxed set */
9174 SCIP_Real transrhs; /**< rhs in relaxed set */
9175 int* origbinvars; /**< associated original binary var for all vars in relaxed set */
9176 int* origcontvars; /**< associated original continuous var for all vars in relaxed set */
9177 SCIP_Real* aggrcoefsbin; /**< aggregation coefficient of the original binary var used to define the
9178 * continuous variable in the relaxed set */
9179 SCIP_Real* aggrcoefscont; /**< aggregation coefficient of the original continuous var used to define the
9180 * continuous variable in the relaxed set */
9181 SCIP_Real* aggrconstants; /**< aggregation constant used to define the continuous variable in the relaxed set */
9183
9184/** get solution value and index of variable lower bound (with binary variable) which is closest to the current LP
9185 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
9186 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
9187 * given variable
9188 */
9189static
9191 SCIP* scip, /**< SCIP data structure */
9192 SCIP_VAR* var, /**< given active problem variable */
9193 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
9194 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
9195 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
9196 * was not used (0) or was not used but is contained in the row (-1) */
9197 SCIP_Real bestsub, /**< closest simple upper bound of given variable */
9198 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
9199 SCIP_Real* closestvlb, /**< pointer to store the LP sol value of the closest variable lower bound */
9200 int* closestvlbidx /**< pointer to store the index of the closest vlb; -1 if no vlb was found */
9201 )
9202{
9203 int nvlbs;
9204 int nbinvars;
9205
9206 assert(scip != NULL);
9207 assert(var != NULL);
9208 assert(bestsub == SCIPvarGetUbGlobal(var) || bestsub == SCIPvarGetUbLocal(var)); /*lint !e777*/
9209 assert(!SCIPisInfinity(scip, bestsub));
9210 assert(!EPSZ(rowcoef, QUAD_EPSILON));
9211 assert(rowcoefs != NULL);
9212 assert(binvarused != NULL);
9213 assert(closestvlb != NULL);
9214 assert(closestvlbidx != NULL);
9215
9216 nvlbs = SCIPvarGetNVlbs(var);
9217 nbinvars = SCIPgetNBinVars(scip);
9218
9219 *closestvlbidx = -1;
9220 *closestvlb = -SCIPinfinity(scip);
9221 if( nvlbs > 0 )
9222 {
9223 SCIP_VAR** vlbvars;
9224 SCIP_Real* vlbcoefs;
9225 SCIP_Real* vlbconsts;
9226 int i;
9227
9228 vlbvars = SCIPvarGetVlbVars(var);
9229 vlbcoefs = SCIPvarGetVlbCoefs(var);
9230 vlbconsts = SCIPvarGetVlbConstants(var);
9231
9232 for( i = 0; i < nvlbs; i++ )
9233 {
9234 SCIP_Real rowcoefbinvar;
9235 SCIP_Real val1;
9236 SCIP_Real val2;
9237 SCIP_Real vlbsol;
9238 SCIP_Real rowcoefsign;
9239 int probidxbinvar;
9240
9241 if( bestsub > vlbconsts[i] )
9242 continue;
9243
9244 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
9245 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
9246 */
9247 if( REALABS(vlbcoefs[i]) > MAXABSVBCOEF )
9248 continue;
9249
9250 /* use only variable lower bounds l~_i * x_i + d_i with x_i binary which are active */
9251 probidxbinvar = SCIPvarGetProbindex(vlbvars[i]);
9252
9253 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
9254 * ensures that the problem index is between 0 and nbinvars - 1
9255 */
9256 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
9257 continue;
9258
9259 assert(SCIPvarIsBinary(vlbvars[i]));
9260
9261 /* check if current variable lower bound l~_i * x_i + d_i imposed on y_j meets the following criteria:
9262 * (let a_j = coefficient of y_j in current row,
9263 * u_j = closest simple upper bound imposed on y_j,
9264 * c_i = coefficient of x_i in current row)
9265 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k yet
9266 * if a_j > 0:
9267 * 1. u_j <= d_i
9268 * 2. a_j ( u_j - d_i ) + c_i <= 0
9269 * 3. a_j l~_i + c_i <= 0
9270 * if a_j < 0:
9271 * 1. u_j <= d_i
9272 * 2. a_j ( u_j - d_i ) + c_i >= 0
9273 * 3. a_j l~_i + c_i >= 0
9274 */
9275
9276 /* has already been used in the SNF relaxation */
9277 if( binvarused[probidxbinvar] == 1 )
9278 continue;
9279
9280 /* get the row coefficient */
9281 {
9282 SCIP_Real QUAD(tmp);
9283 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
9284 rowcoefbinvar = QUAD_TO_DBL(tmp);
9285 }
9286 rowcoefsign = COPYSIGN(1.0, rowcoef);
9287
9288 val2 = rowcoefsign * ((rowcoef * vlbcoefs[i]) + rowcoefbinvar);
9289
9290 /* variable lower bound does not meet criteria */
9291 if( val2 > 0.0 || SCIPisInfinity(scip, -val2) )
9292 continue;
9293
9294 val1 = rowcoefsign * ((rowcoef * (bestsub - vlbconsts[i])) + rowcoefbinvar);
9295
9296 /* variable lower bound does not meet criteria */
9297 if( val1 > 0.0 )
9298 continue;
9299
9300 vlbsol = vlbcoefs[i] * SCIPgetSolVal(scip, sol, vlbvars[i]) + vlbconsts[i];
9301 if( vlbsol > *closestvlb )
9302 {
9303 *closestvlb = vlbsol;
9304 *closestvlbidx = i;
9305 }
9306 assert(*closestvlbidx >= 0);
9307 }
9308 }
9309
9310 return SCIP_OKAY;
9311}
9312
9313/** get LP solution value and index of variable upper bound (with binary variable) which is closest to the current LP
9314 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
9315 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
9316 * given variable
9317 */
9318static
9320 SCIP* scip, /**< SCIP data structure */
9321 SCIP_VAR* var, /**< given active problem variable */
9322 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
9323 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
9324 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
9325 * was not used (0) or was not used but is contained in the row (-1)
9326 */
9327 SCIP_Real bestslb, /**< closest simple lower bound of given variable */
9328 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
9329 SCIP_Real* closestvub, /**< pointer to store the LP sol value of the closest variable upper bound */
9330 int* closestvubidx /**< pointer to store the index of the closest vub; -1 if no vub was found */
9331 )
9332{
9333 int nvubs;
9334 int nbinvars;
9335
9336 assert(scip != NULL);
9337 assert(var != NULL);
9338 assert(bestslb == SCIPvarGetLbGlobal(var) || bestslb == SCIPvarGetLbLocal(var)); /*lint !e777*/
9339 assert(!SCIPisInfinity(scip, - bestslb));
9340 assert(!EPSZ(rowcoef, QUAD_EPSILON));
9341 assert(rowcoefs != NULL);
9342 assert(binvarused != NULL);
9343 assert(closestvub != NULL);
9344 assert(closestvubidx != NULL);
9345
9346 nvubs = SCIPvarGetNVubs(var);
9347 nbinvars = SCIPgetNBinVars(scip);
9348
9349 *closestvubidx = -1;
9350 *closestvub = SCIPinfinity(scip);
9351 if( nvubs > 0 )
9352 {
9353 SCIP_VAR** vubvars;
9354 SCIP_Real* vubcoefs;
9355 SCIP_Real* vubconsts;
9356 int i;
9357
9358 vubvars = SCIPvarGetVubVars(var);
9359 vubcoefs = SCIPvarGetVubCoefs(var);
9360 vubconsts = SCIPvarGetVubConstants(var);
9361
9362 for( i = 0; i < nvubs; i++ )
9363 {
9364 SCIP_Real rowcoefbinvar;
9365 SCIP_Real val1;
9366 SCIP_Real val2;
9367 SCIP_Real vubsol;
9368 SCIP_Real rowcoefsign;
9369 int probidxbinvar;
9370
9371 if( bestslb < vubconsts[i] )
9372 continue;
9373
9374 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
9375 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
9376 */
9377 if( REALABS(vubcoefs[i]) > MAXABSVBCOEF )
9378 continue;
9379
9380 /* use only variable upper bound u~_i * x_i + d_i with x_i binary and which are active */
9381 probidxbinvar = SCIPvarGetProbindex(vubvars[i]);
9382
9383 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
9384 * ensures that the problem index is between 0 and nbinvars - 1
9385 */
9386 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
9387 continue;
9388
9389 assert(SCIPvarIsBinary(vubvars[i]));
9390
9391 /* checks if current variable upper bound u~_i * x_i + d_i meets the following criteria
9392 * (let a_j = coefficient of y_j in current row,
9393 * l_j = closest simple lower bound imposed on y_j,
9394 * c_i = coefficient of x_i in current row)
9395 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k
9396 * if a > 0:
9397 * 1. l_j >= d_i
9398 * 2. a_j ( l_i - d_i ) + c_i >= 0
9399 * 3. a_j u~_i + c_i >= 0
9400 * if a < 0:
9401 * 1. l_j >= d_i
9402 * 2. a_j ( l_j - d_i ) + c_i <= 0
9403 * 3. a_j u~_i + c_i <= 0
9404 */
9405
9406 /* has already been used in the SNF relaxation */
9407 if( binvarused[probidxbinvar] == 1 )
9408 continue;
9409
9410 /* get the row coefficient */
9411 {
9412 SCIP_Real QUAD(tmp);
9413 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
9414 rowcoefbinvar = QUAD_TO_DBL(tmp);
9415 }
9416 rowcoefsign = COPYSIGN(1.0, rowcoef);
9417
9418 val2 = rowcoefsign * ((rowcoef * vubcoefs[i]) + rowcoefbinvar);
9419
9420 /* variable upper bound does not meet criteria */
9421 if( val2 < 0.0 || SCIPisInfinity(scip, val2) )
9422 continue;
9423
9424 val1 = rowcoefsign * ((rowcoef * (bestslb - vubconsts[i])) + rowcoefbinvar);
9425
9426 /* variable upper bound does not meet criteria */
9427 if( val1 < 0.0 )
9428 continue;
9429
9430 vubsol = vubcoefs[i] * SCIPgetSolVal(scip, sol, vubvars[i]) + vubconsts[i];
9431 if( vubsol < *closestvub )
9432 {
9433 *closestvub = vubsol;
9434 *closestvubidx = i;
9435 }
9436 assert(*closestvubidx >= 0);
9437 }
9438 }
9439
9440 return SCIP_OKAY;
9441}
9442
9443/** determines the bounds to use for constructing the single-node-flow relaxation of a variable in
9444 * the given row.
9445 */
9446static
9448 SCIP* scip, /**< SCIP data structure */
9449 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
9450 SCIP_VAR** vars, /**< array of problem variables */
9451 SCIP_Real* rowcoefs, /**< (dense) array of variable coefficients in the row */
9452 int* rowinds, /**< array with positions of non-zero values in the rowcoefs array */
9453 int varposinrow, /**< position of variable in the rowinds array for which the bounds should be determined */
9454 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
9455 * was not used (0) or was not used but is contained in the row (-1)
9456 */
9457 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
9458 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
9459 SCIP_Real* bestlb, /**< pointer to store best lower bound for transformation */
9460 SCIP_Real* bestub, /**< pointer to store best upper bound for transformation */
9461 SCIP_Real* bestslb, /**< pointer to store best simple lower bound for transformation */
9462 SCIP_Real* bestsub, /**< pointer to store best simple upper bound for transformation */
9463 int* bestlbtype, /**< pointer to store type of best lower bound (-2: local bound, -1: global bound, >= 0 variable bound index) */
9464 int* bestubtype, /**< pointer to store type of best upper bound (-2: local bound, -1: global bound, >= 0 variable bound index) */
9465 int* bestslbtype, /**< pointer to store type of best simple lower bound */
9466 int* bestsubtype, /**< pointer to store type of best simple upper bound */
9467 SCIP_BOUNDTYPE* selectedbounds, /**< pointer to store the preferred bound for the transformation */
9468 SCIP_Bool* freevariable /**< pointer to store if variable is a free variable */
9469 )
9470{
9471 SCIP_VAR* var;
9472
9473 SCIP_Real rowcoef;
9474 SCIP_Real solval;
9475
9476 int probidx;
9477
9478 bestlb[varposinrow] = -SCIPinfinity(scip);
9479 bestub[varposinrow] = SCIPinfinity(scip);
9480 bestlbtype[varposinrow] = -3;
9481 bestubtype[varposinrow] = -3;
9482
9483 probidx = rowinds[varposinrow];
9484 var = vars[probidx];
9485 {
9486 SCIP_Real QUAD(tmp);
9487 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidx);
9488 rowcoef = QUAD_TO_DBL(tmp);
9489 }
9490
9491 assert(!EPSZ(rowcoef, QUAD_EPSILON));
9492
9493 /* get closest simple lower bound and closest simple upper bound */
9494 SCIP_CALL( findBestLb(scip, var, sol, 0, allowlocal, &bestslb[varposinrow], &bestslbtype[varposinrow]) );
9495 SCIP_CALL( findBestUb(scip, var, sol, 0, allowlocal, &bestsub[varposinrow], &bestsubtype[varposinrow]) );
9496
9497 /* do not use too large bounds */
9498 if( bestslb[varposinrow] <= -MAXBOUND )
9499 bestslb[varposinrow] = -SCIPinfinity(scip);
9500
9501 if( bestsub[varposinrow] >= MAXBOUND )
9502 bestsub[varposinrow] = SCIPinfinity(scip);
9503
9504 solval = SCIPgetSolVal(scip, sol, var);
9505
9506 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g(%d),%g(%d)]>:\n", varposinrow, rowcoef, SCIPvarGetName(var), probidx,
9507 solval, bestslb[varposinrow], bestslbtype[varposinrow], bestsub[varposinrow], bestsubtype[varposinrow]);
9508
9509 /* mixed integer set cannot be relaxed to 0-1 single node flow set because both simple bounds are -infinity
9510 * and infinity, respectively
9511 */
9512 if( SCIPisInfinity(scip, -bestslb[varposinrow]) && SCIPisInfinity(scip, bestsub[varposinrow]) )
9513 {
9514 *freevariable = TRUE;
9515 return SCIP_OKAY;
9516 }
9517
9518 /* get closest lower bound that can be used to define the real variable y'_j in the 0-1 single node flow
9519 * relaxation
9520 */
9521 if( !SCIPisInfinity(scip, bestsub[varposinrow]) )
9522 {
9523 bestlb[varposinrow] = bestslb[varposinrow];
9524 bestlbtype[varposinrow] = bestslbtype[varposinrow];
9525
9527 {
9528 SCIP_Real bestvlb;
9529 int bestvlbidx;
9530
9531 SCIP_CALL( getClosestVlb(scip, var, sol, rowcoefs, binvarused, bestsub[varposinrow], rowcoef, &bestvlb, &bestvlbidx) );
9532 if( SCIPisGT(scip, bestvlb, bestlb[varposinrow]) )
9533 {
9534 bestlb[varposinrow] = bestvlb;
9535 bestlbtype[varposinrow] = bestvlbidx;
9536 }
9537 }
9538 }
9539
9540 /* get closest upper bound that can be used to define the real variable y'_j in the 0-1 single node flow
9541 * relaxation
9542 */
9543 if( !SCIPisInfinity(scip, -bestslb[varposinrow]) )
9544 {
9545 bestub[varposinrow] = bestsub[varposinrow];
9546 bestubtype[varposinrow] = bestsubtype[varposinrow];
9547
9549 {
9550 SCIP_Real bestvub;
9551 int bestvubidx;
9552
9553 SCIP_CALL( getClosestVub(scip, var, sol, rowcoefs, binvarused, bestslb[varposinrow], rowcoef, &bestvub, &bestvubidx) );
9554 if( SCIPisLT(scip, bestvub, bestub[varposinrow]) )
9555 {
9556 bestub[varposinrow] = bestvub;
9557 bestubtype[varposinrow] = bestvubidx;
9558 }
9559 }
9560 }
9561 SCIPdebugMsg(scip, " bestlb=%g(%d), bestub=%g(%d)\n", bestlb[varposinrow], bestlbtype[varposinrow], bestub[varposinrow], bestubtype[varposinrow]);
9562
9563 /* mixed integer set cannot be relaxed to 0-1 single node flow set because there are no suitable bounds
9564 * to define the transformed variable y'_j
9565 */
9566 if( SCIPisInfinity(scip, -bestlb[varposinrow]) && SCIPisInfinity(scip, bestub[varposinrow]) )
9567 {
9568 *freevariable = TRUE;
9569 return SCIP_OKAY;
9570 }
9571
9572 *freevariable = FALSE;
9573
9574 /* select best upper bound if it is closer to the LP value of y_j and best lower bound otherwise and use this bound
9575 * to define the real variable y'_j with 0 <= y'_j <= u'_j x_j in the 0-1 single node flow relaxation;
9576 * prefer variable bounds
9577 */
9578 if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) && bestlbtype[varposinrow] >= 0 )
9579 {
9580 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
9581 }
9582 else if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow])
9583 && bestubtype[varposinrow] >= 0 )
9584 {
9585 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
9586 }
9587 else if( SCIPisLE(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) )
9588 {
9589 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
9590 }
9591 else
9592 {
9593 assert(SCIPisGT(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]));
9594 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
9595 }
9596
9597 if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_LOWER && bestlbtype[varposinrow] >= 0 )
9598 {
9599 int vlbvarprobidx;
9600 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
9601
9602 /* mark binary variable of vlb so that it is not used for other continuous variables
9603 * by setting it's position in the aggrrow to a negative value
9604 */
9605 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[varposinrow]]);
9606 binvarused[vlbvarprobidx] = 1;
9607 }
9608 else if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_UPPER && bestubtype[varposinrow] >= 0 )
9609 {
9610 int vubvarprobidx;
9611 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
9612
9613 /* mark binary variable of vub 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 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[varposinrow]]);
9617 binvarused[vubvarprobidx] = 1;
9618 }
9619
9620 return SCIP_OKAY; /*lint !e438*/
9621}
9622
9623/** construct a 0-1 single node flow relaxation (with some additional simple constraints) of a mixed integer set
9624 * corresponding to the given aggrrow a * x <= rhs
9625 */
9626static
9628 SCIP* scip, /**< SCIP data structure */
9629 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
9630 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
9631 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
9632 SCIP_Real* rowcoefs, /**< array of coefficients of row */
9633 QUAD(SCIP_Real rowrhs), /**< pointer to right hand side of row */
9634 int* rowinds, /**< array of variables problem indices for non-zero coefficients in row */
9635 int nnz, /**< number of non-zeros in row */
9636 SNF_RELAXATION* snf, /**< stores the sign of the transformed variable in summation */
9637 SCIP_Bool* success, /**< stores whether the transformation was valid */
9638 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
9639 )
9640{
9641 SCIP_VAR** vars;
9642 int i;
9643 int nnonbinvarsrow;
9644 int8_t* binvarused;
9645 int nbinvars;
9646 SCIP_Real QUAD(transrhs);
9647
9648 /* arrays to store the selected bound for each non-binary variable in the row */
9649 SCIP_Real* bestlb;
9650 SCIP_Real* bestub;
9651 SCIP_Real* bestslb;
9652 SCIP_Real* bestsub;
9653 int* bestlbtype;
9654 int* bestubtype;
9655 int* bestslbtype;
9656 int* bestsubtype;
9657 SCIP_BOUNDTYPE* selectedbounds;
9658
9659 *success = FALSE;
9660
9661 SCIPdebugMsg(scip, "--------------------- construction of SNF relaxation ------------------------------------\n");
9662
9663 nbinvars = SCIPgetNBinVars(scip);
9664 vars = SCIPgetVars(scip);
9665
9666 SCIP_CALL( SCIPallocBufferArray(scip, &bestlb, nnz) );
9667 SCIP_CALL( SCIPallocBufferArray(scip, &bestub, nnz) );
9668 SCIP_CALL( SCIPallocBufferArray(scip, &bestslb, nnz) );
9669 SCIP_CALL( SCIPallocBufferArray(scip, &bestsub, nnz) );
9670 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtype, nnz) );
9671 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtype, nnz) );
9672 SCIP_CALL( SCIPallocBufferArray(scip, &bestslbtype, nnz) );
9673 SCIP_CALL( SCIPallocBufferArray(scip, &bestsubtype, nnz) );
9674 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, nnz) );
9675
9676 /* sort descending to have continuous variables first */
9677 SCIPsortDownInt(rowinds, nnz);
9678
9679 /* array to store whether a binary variable is in the row (-1) or has been used (1) due to variable bound usage */
9680 SCIP_CALL( SCIPallocCleanBufferArray(scip, &binvarused, nbinvars) );
9681
9682 for( i = nnz - 1; i >= 0 && rowinds[i] < nbinvars; --i )
9683 binvarused[rowinds[i]] = -1;
9684
9685 nnonbinvarsrow = i + 1;
9686 /* determine the bounds to use for transforming the non-binary variables */
9687 for( i = 0; i < nnonbinvarsrow; ++i )
9688 {
9689 SCIP_Bool freevariable;
9690
9691 assert(rowinds[i] >= nbinvars);
9692
9693 SCIP_CALL( determineBoundForSNF(scip, sol, vars, rowcoefs, rowinds, i, binvarused, allowlocal, boundswitch,
9694 bestlb, bestub, bestslb, bestsub, bestlbtype, bestubtype, bestslbtype, bestsubtype, selectedbounds, &freevariable) );
9695
9696 if( freevariable )
9697 {
9698 int j;
9699
9700 /* clear binvarused at indices of binary variables of row */
9701 for( j = nnz - 1; j >= nnonbinvarsrow; --j )
9702 binvarused[rowinds[j]] = 0;
9703
9704 /* clear binvarused at indices of selected variable bounds */
9705 for( j = 0; j < i; ++j )
9706 {
9707 if( selectedbounds[j] == SCIP_BOUNDTYPE_LOWER && bestlbtype[j] >= 0 )
9708 {
9709 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(vars[rowinds[j]]);
9710 binvarused[SCIPvarGetProbindex(vlbvars[bestlbtype[j]])] = 0;
9711 }
9712 else if( selectedbounds[j] == SCIP_BOUNDTYPE_UPPER && bestubtype[j] >= 0 )
9713 {
9714 SCIP_VAR** vubvars = SCIPvarGetVubVars(vars[rowinds[j]]);
9715 binvarused[SCIPvarGetProbindex(vubvars[bestubtype[j]])] = 0;
9716 }
9717 }
9718
9719 /* terminate */
9720 goto TERMINATE;
9721 }
9722 }
9723
9724 *localbdsused = FALSE;
9725 QUAD_ASSIGN_Q(transrhs, rowrhs);
9726 snf->ntransvars = 0;
9727
9728 assert(snf->transvarcoefs != NULL); /* for lint */
9729 assert(snf->transvarvubcoefs != NULL);
9730 assert(snf->transbinvarsolvals != NULL);
9731 assert(snf->transcontvarsolvals != NULL);
9732 assert(snf->aggrconstants != NULL);
9733 assert(snf->aggrcoefscont != NULL);
9734 assert(snf->origcontvars != NULL);
9735 assert(snf->origbinvars != NULL);
9736 assert(snf->aggrcoefsbin != NULL);
9737
9738 /* transform non-binary variables */
9739 for( i = 0; i < nnonbinvarsrow; ++i )
9740 {
9741 SCIP_VAR* var;
9742 SCIP_Real QUAD(rowcoef);
9743 SCIP_Real solval;
9744 int probidx;
9745
9746 probidx = rowinds[i];
9747 var = vars[probidx];
9748 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
9749 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
9750 solval = SCIPgetSolVal(scip, sol, var);
9751
9752 assert(probidx >= nbinvars);
9753
9754 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
9755 {
9756 /* use bestlb to define y'_j */
9757
9758 assert(!SCIPisInfinity(scip, bestsub[i]));
9759 assert(!SCIPisInfinity(scip, - bestlb[i]));
9760 assert(bestsubtype[i] == -1 || bestsubtype[i] == -2);
9761 assert(bestlbtype[i] > -3 && bestlbtype[i] < SCIPvarGetNVlbs(var));
9762
9763 /* store for y_j that bestlb is the bound used to define y'_j and that y'_j is the associated real variable
9764 * in the relaxed set
9765 */
9766 snf->origcontvars[snf->ntransvars] = probidx;
9767
9768 if( bestlbtype[i] < 0 )
9769 {
9770 SCIP_Real QUAD(val);
9771 SCIP_Real QUAD(contsolval);
9772 SCIP_Real QUAD(rowcoeftimesbestsub);
9773
9774 /* use simple lower bound in bestlb = l_j <= y_j <= u_j = bestsub to define
9775 * 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
9776 * 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,
9777 * put j into the set
9778 * N2 if a_j > 0
9779 * N1 if a_j < 0
9780 * and update the right hand side of the constraint in the relaxation
9781 * rhs = rhs - a_j u_j
9782 */
9783 SCIPquadprecSumDD(val, bestsub[i], -bestlb[i]);
9784 SCIPquadprecProdQQ(val, val, rowcoef);
9785 SCIPquadprecSumDD(contsolval, solval, -bestsub[i]);
9786 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
9787
9788 if( bestlbtype[i] == -2 || bestsubtype[i] == -2 )
9789 *localbdsused = TRUE;
9790
9791 SCIPquadprecProdQD(rowcoeftimesbestsub, rowcoef, bestsub[i]);
9792
9793 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
9794 snf->origbinvars[snf->ntransvars] = -1;
9795 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
9796
9797 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
9798 {
9799 snf->transvarcoefs[snf->ntransvars] = - 1;
9800 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
9801 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
9802 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
9803
9804 /* aggregation information for y'_j */
9805 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestsub);
9806 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
9807 }
9808 else
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 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestsub);
9820
9821 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
9822 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
9823 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestsub), QUAD_TO_DBL(rowcoef), bestsub[i], QUAD_TO_DBL(transrhs));
9824 }
9825 else
9826 {
9827 SCIP_Real QUAD(rowcoefbinary);
9828 SCIP_Real varsolvalbinary;
9829 SCIP_Real QUAD(val);
9830 SCIP_Real QUAD(contsolval);
9831 SCIP_Real QUAD(rowcoeftimesvlbconst);
9832 int vlbvarprobidx;
9833
9834 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
9835 SCIP_Real* vlbconsts = SCIPvarGetVlbConstants(var);
9836 SCIP_Real* vlbcoefs = SCIPvarGetVlbCoefs(var);
9837
9838 /* use variable lower bound in bestlb = l~_j x_j + d_j <= y_j <= u_j = bestsub to define
9839 * 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
9840 * 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,
9841 * where c_j is the coefficient of x_j in the row, put j into the set
9842 * N2 if a_j > 0
9843 * N1 if a_j < 0
9844 * and update the right hand side of the constraint in the relaxation
9845 * rhs = rhs - a_j d_j
9846 */
9847
9848 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[i]]);
9849 assert(binvarused[vlbvarprobidx] == 1);
9850 assert(vlbvarprobidx < nbinvars);
9851
9852 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vlbvarprobidx);
9853 varsolvalbinary = SCIPgetSolVal(scip, sol, vlbvars[bestlbtype[i]]);
9854
9855 SCIPquadprecProdQD(val, rowcoef, vlbcoefs[bestlbtype[i]]);
9856 SCIPquadprecSumQQ(val, val, rowcoefbinary);
9857 {
9858 SCIP_Real QUAD(tmp);
9859
9860 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
9861 SCIPquadprecSumDD(contsolval, solval, - vlbconsts[bestlbtype[i]]);
9862 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
9863 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
9864 }
9865
9866 SCIPquadprecProdQD(rowcoeftimesvlbconst, rowcoef, vlbconsts[bestlbtype[i]]);
9867
9868 /* clear the binvarpos array, since the variable has been processed */
9869 binvarused[vlbvarprobidx] = 0;
9870
9871 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
9872 snf->origbinvars[snf->ntransvars] = vlbvarprobidx;
9873
9874 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
9875 {
9876 snf->transvarcoefs[snf->ntransvars] = - 1;
9877 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
9878 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
9879 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
9880
9881 /* aggregation information for y'_j */
9882 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
9883 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
9884 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvlbconst);
9885 }
9886 else
9887 {
9888 snf->transvarcoefs[snf->ntransvars] = 1;
9889 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
9890 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
9891 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
9892
9893 /* aggregation information for y'_j */
9894 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
9895 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
9896 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvlbconst);
9897 }
9898 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvlbconst);
9899
9900 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
9901 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
9902 snf->ntransvars, SCIPvarGetName(vlbvars[bestlbtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvlbconst), QUAD_TO_DBL(rowcoef),
9903 vlbconsts[bestlbtype[i]], QUAD_TO_DBL(transrhs) );
9904 }
9905 }
9906 else
9907 {
9908 /* use bestub to define y'_j */
9909
9910 assert(!SCIPisInfinity(scip, bestub[i]));
9911 assert(!SCIPisInfinity(scip, - bestslb[i]));
9912 assert(bestslbtype[i] == -1 || bestslbtype[i] == -2);
9913 assert(bestubtype[i] > -3 && bestubtype[i] < SCIPvarGetNVubs(var));
9914
9915 /* store for y_j that y'_j is the associated real variable
9916 * in the relaxed set
9917 */
9918 snf->origcontvars[snf->ntransvars] = probidx;
9919
9920 if( bestubtype[i] < 0 )
9921 {
9922 SCIP_Real QUAD(val);
9923 SCIP_Real QUAD(contsolval);
9924 SCIP_Real QUAD(rowcoeftimesbestslb);
9925
9926 /* use simple upper bound in bestslb = l_j <= y_j <= u_j = bestub to define
9927 * 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
9928 * 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,
9929 * put j into the set
9930 * N1 if a_j > 0
9931 * N2 if a_j < 0
9932 * and update the right hand side of the constraint in the relaxation
9933 * rhs = rhs - a_j l_j
9934 */
9935 SCIPquadprecSumDD(val, bestub[i], - bestslb[i]);
9936 SCIPquadprecProdQQ(val, val, rowcoef);
9937 SCIPquadprecSumDD(contsolval, solval, - bestslb[i]);
9938 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
9939
9940 if( bestubtype[i] == -2 || bestslbtype[i] == -2 )
9941 *localbdsused = TRUE;
9942
9943 SCIPquadprecProdQD(rowcoeftimesbestslb, rowcoef, bestslb[i]);
9944
9945 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
9946 snf->origbinvars[snf->ntransvars] = -1;
9947 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
9948
9949 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
9950 {
9951 snf->transvarcoefs[snf->ntransvars] = 1;
9952 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
9953 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
9954 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
9955
9956 /* aggregation information for y'_j */
9957 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
9958 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestslb);
9959 }
9960 else
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 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestslb);
9972
9973 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., Y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
9974 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
9975 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestslb), QUAD_TO_DBL(rowcoef), bestslb[i], QUAD_TO_DBL(transrhs));
9976 }
9977 else
9978 {
9979 SCIP_Real QUAD(rowcoefbinary);
9980 SCIP_Real varsolvalbinary;
9981 SCIP_Real QUAD(val);
9982 SCIP_Real QUAD(contsolval);
9983 SCIP_Real QUAD(rowcoeftimesvubconst);
9984 int vubvarprobidx;
9985
9986 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
9987 SCIP_Real* vubconsts = SCIPvarGetVubConstants(var);
9988 SCIP_Real* vubcoefs = SCIPvarGetVubCoefs(var);
9989
9990 /* use variable upper bound in bestslb = l_j <= y_j <= u~_j x_j + d_j = bestub to define
9991 * 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
9992 * 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,
9993 * where c_j is the coefficient of x_j in the row, put j into the set
9994 * N1 if a_j > 0
9995 * N2 if a_j < 0
9996 * and update the right hand side of the constraint in the relaxation
9997 * rhs = rhs - a_j d_j
9998 */
9999
10000 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[i]]);
10001 assert(binvarused[vubvarprobidx] == 1);
10002 assert(vubvarprobidx < nbinvars);
10003
10004 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vubvarprobidx);
10005 varsolvalbinary = SCIPgetSolVal(scip, sol, vubvars[bestubtype[i]]);
10006
10007 /* clear the binvarpos array, since the variable has been processed */
10008 binvarused[vubvarprobidx] = 0;
10009
10010 SCIPquadprecProdQD(val, rowcoef, vubcoefs[bestubtype[i]]);
10011 SCIPquadprecSumQQ(val, val, rowcoefbinary);
10012 {
10013 SCIP_Real QUAD(tmp);
10014 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
10015 SCIPquadprecSumDD(contsolval, solval, - vubconsts[bestubtype[i]]);
10016 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
10017 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
10018 }
10019
10020 SCIPquadprecProdQD(rowcoeftimesvubconst, rowcoef, vubconsts[bestubtype[i]]);
10021 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
10022 snf->origbinvars[snf->ntransvars] = vubvarprobidx;
10023
10024 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
10025 {
10026 snf->transvarcoefs[snf->ntransvars] = 1;
10027 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
10028 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
10029 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
10030
10031 /* aggregation information for y'_j */
10032 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
10033 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
10034 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvubconst);
10035 }
10036 else
10037 {
10038 snf->transvarcoefs[snf->ntransvars] = - 1;
10039 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
10040 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
10041 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
10042
10043 /* aggregation information for y'_j */
10044 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
10045 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
10046 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvubconst);
10047 }
10048 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvubconst);
10049
10050 /* store for x_j that y'_j is the associated real variable in the 0-1 single node flow relaxation */
10051
10052 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
10053 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
10054 snf->ntransvars, SCIPvarGetName(vubvars[bestubtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvubconst), QUAD_TO_DBL(rowcoef),
10055 vubconsts[bestubtype[i]], QUAD_TO_DBL(transrhs));
10056 }
10057 }
10058
10059 /* make sure the coefficient is not negative due to small numerical rounding errors */
10060 assert(snf->transvarvubcoefs[snf->ntransvars] > -QUAD_EPSILON);
10061 snf->transvarvubcoefs[snf->ntransvars] = MAX(snf->transvarvubcoefs[snf->ntransvars], 0.0);
10062
10063 ++snf->ntransvars;
10064 }
10065
10066 snf->transrhs = QUAD_TO_DBL(transrhs);
10067
10068 /* transform remaining binary variables of row */
10069 for( i = nnonbinvarsrow; i < nnz; ++i )
10070 {
10071 SCIP_VAR* var;
10072 SCIP_Real QUAD(rowcoef);
10073 int probidx;
10074 SCIP_Real val;
10075 SCIP_Real contsolval;
10076 SCIP_Real varsolval;
10077
10078 probidx = rowinds[i];
10079 /* variable should be binary */
10080 assert(probidx >= 0);
10081 assert(probidx < nbinvars);
10082
10083 /* binary variable was processed together with a non-binary variable */
10084 if( binvarused[probidx] == 0 )
10085 continue;
10086
10087 /* binary variable was not processed yet, so the binvarused value sould be -1 */
10088 assert(binvarused[probidx] == -1);
10089
10090 /* set binvarused to zero since it has been processed */
10091 binvarused[probidx] = 0;
10092
10093 var = vars[probidx];
10094 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
10095 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
10096
10097 varsolval = SCIPgetSolVal(scip, sol, var);
10098 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g, %g]>:\n", i, QUAD_TO_DBL(rowcoef), SCIPvarGetName(var), probidx, varsolval,
10100
10101 /* define
10102 * y'_j = c_j x_j with 0 <= y'_j <= c_j x_j if c_j > 0
10103 * y'_j = - c_j x_j with 0 <= y'_j <= - c_j x_j if c_j < 0,
10104 * where c_j is the coefficient of x_j in the row and put j into the set
10105 * N1 if c_j > 0
10106 * N2 if c_j < 0.
10107 */
10108 val = QUAD_TO_DBL(rowcoef);
10109 contsolval = QUAD_TO_DBL(rowcoef) * varsolval;
10110
10111 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
10112 snf->origbinvars[snf->ntransvars] = probidx;
10113 snf->origcontvars[snf->ntransvars] = -1;
10114 snf->aggrcoefscont[snf->ntransvars] = 0.0;
10115 snf->aggrconstants[snf->ntransvars] = 0.0;
10116
10117 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
10118 {
10119 snf->transvarcoefs[snf->ntransvars] = 1;
10120 snf->transvarvubcoefs[snf->ntransvars] = val;
10121 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
10122 snf->transcontvarsolvals[snf->ntransvars] = contsolval;
10123
10124 /* aggregation information for y'_j */
10125 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
10126 }
10127 else
10128 {
10129 snf->transvarcoefs[snf->ntransvars] = - 1;
10130 snf->transvarvubcoefs[snf->ntransvars] = - val;
10131 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
10132 snf->transcontvarsolvals[snf->ntransvars] = - contsolval;
10133
10134 /* aggregation information for y'_j */
10135 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
10136 }
10137
10138 assert(snf->transvarcoefs[snf->ntransvars] == 1 || snf->transvarcoefs[snf->ntransvars] == - 1 );
10139 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[snf->ntransvars], 0.0)
10140 && SCIPisFeasLE(scip, snf->transbinvarsolvals[snf->ntransvars], 1.0));
10141 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[snf->ntransvars], 0.0)
10143
10144 SCIPdebugMsg(scip, " --> ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s))\n", snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars,
10145 snf->transvarvubcoefs[snf->ntransvars], snf->ntransvars, SCIPvarGetName(var) );
10146
10147 /* updates number of variables in transformed problem */
10148 snf->ntransvars++;
10149 }
10150
10151 /* construction was successful */
10152 *success = TRUE;
10153
10154#ifdef SCIP_DEBUG
10155 SCIPdebugMsg(scip, "constraint in constructed 0-1 single node flow relaxation: ");
10156 for( i = 0; i < snf->ntransvars; i++ )
10157 {
10158 SCIPdebugMsgPrint(scip, "%s y'_%d ", snf->transvarcoefs[i] == 1 ? "+" : "-", i);
10159 }
10160 SCIPdebugMsgPrint(scip, "<= %g\n", snf->transrhs);
10161#endif
10162
10163 TERMINATE:
10164
10165 SCIPfreeCleanBufferArray(scip, &binvarused);
10166 SCIPfreeBufferArray(scip, &selectedbounds);
10167 SCIPfreeBufferArray(scip, &bestsubtype);
10168 SCIPfreeBufferArray(scip, &bestslbtype);
10169 SCIPfreeBufferArray(scip, &bestubtype);
10170 SCIPfreeBufferArray(scip, &bestlbtype);
10171 SCIPfreeBufferArray(scip, &bestsub);
10172 SCIPfreeBufferArray(scip, &bestslb);
10173 SCIPfreeBufferArray(scip, &bestub);
10174 SCIPfreeBufferArray(scip, &bestlb);
10175
10176 return SCIP_OKAY;
10177}
10178
10179/** allocate buffer arrays for storing the single-node-flow relaxation */
10180static
10182 SCIP* scip, /**< SCIP data structure */
10183 SNF_RELAXATION* snf, /**< pointer to snf relaxation to be destroyed */
10184 int nvars /**< number of active problem variables */
10185 )
10186{
10196
10197 return SCIP_OKAY;
10198}
10199
10200/** free buffer arrays for storing the single-node-flow relaxation */
10201static
10203 SCIP* scip, /**< SCIP data structure */
10204 SNF_RELAXATION* snf /**< pointer to snf relaxation to be destroyed */
10205 )
10206{
10216}
10217
10218/** solve knapsack problem in maximization form with "<" constraint approximately by greedy; if needed, one can provide
10219 * arrays to store all selected items and all not selected items
10220 */
10221static
10223 SCIP* scip, /**< SCIP data structure */
10224 int nitems, /**< number of available items */
10225 SCIP_Real* weights, /**< item weights */
10226 SCIP_Real* profits, /**< item profits */
10227 SCIP_Real capacity, /**< capacity of knapsack */
10228 int* items, /**< item numbers */
10229 int* solitems, /**< array to store items in solution, or NULL */
10230 int* nonsolitems, /**< array to store items not in solution, or NULL */
10231 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
10232 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
10233 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
10234 )
10235{
10236 SCIP_Real* tempsort;
10237 SCIP_Real solitemsweight;
10238 SCIP_Real mediancapacity;
10239 int j;
10240 int i;
10241 int criticalitem;
10242
10243 assert(weights != NULL);
10244 assert(profits != NULL);
10245 assert(SCIPisFeasGE(scip, capacity, 0.0));
10246 assert(!SCIPisInfinity(scip, capacity));
10247 assert(items != NULL);
10248 assert(nitems >= 0);
10249
10250 if( solitems != NULL )
10251 {
10252 *nsolitems = 0;
10253 *nnonsolitems = 0;
10254 }
10255 if( solval != NULL )
10256 *solval = 0.0;
10257
10258 /* allocate memory for temporary array used for sorting; array should contain profits divided by corresponding weights (p_1 / w_1 ... p_n / w_n )*/
10259 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
10260
10261 /* initialize temporary array */
10262 for( i = nitems - 1; i >= 0; --i )
10263 tempsort[i] = profits[i] / weights[i];
10264
10265 /* decrease capacity slightly to make it tighter than the original capacity */
10266 mediancapacity = capacity * (1 - SCIPfeastol(scip));
10267
10268 /* rearrange items around */
10269 SCIPselectWeightedDownRealRealInt(tempsort, profits, items, weights, mediancapacity, nitems, &criticalitem);
10270
10271 /* free temporary array */
10272 SCIPfreeBufferArray(scip, &tempsort);
10273
10274 /* select items as long as they fit into the knapsack */
10275 solitemsweight = 0.0;
10276 for( j = 0; j < nitems && SCIPisFeasLT(scip, solitemsweight + weights[j], capacity); j++ )
10277 {
10278 if( solitems != NULL )
10279 {
10280 solitems[*nsolitems] = items[j];
10281 (*nsolitems)++;
10282 }
10283 if( solval != NULL )
10284 (*solval) += profits[j];
10285 solitemsweight += weights[j];
10286 }
10287
10288 /* continue to put items into the knapsack if they entirely fit */
10289 for( ; j < nitems; j++ )
10290 {
10291 if( SCIPisFeasLT(scip, solitemsweight + weights[j], capacity) )
10292 {
10293 if( solitems != NULL )
10294 {
10295 solitems[*nsolitems] = items[j];
10296 (*nsolitems)++;
10297 }
10298 if( solval != NULL )
10299 (*solval) += profits[j];
10300 solitemsweight += weights[j];
10301 }
10302 else if( solitems != NULL )
10303 {
10304 nonsolitems[*nnonsolitems] = items[j];
10305 (*nnonsolitems)++;
10306 }
10307 }
10308
10309 return SCIP_OKAY;
10310}
10311
10312
10313/** build the flow cover which corresponds to the given exact or approximate solution of KP^SNF; given unfinished
10314 * flow cover contains variables which have been fixed in advance
10315 */
10316static
10318 SCIP* scip, /**< SCIP data structure */
10319 int* coefs, /**< coefficient of all real variables in N1&N2 */
10320 SCIP_Real* vubcoefs, /**< coefficient in vub of all real variables in N1&N2 */
10321 SCIP_Real rhs, /**< right hand side of 0-1 single node flow constraint */
10322 int* solitems, /**< items in knapsack */
10323 int* nonsolitems, /**< items not in knapsack */
10324 int nsolitems, /**< number of items in knapsack */
10325 int nnonsolitems, /**< number of items not in knapsack */
10326 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
10327 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
10328 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
10329 QUAD(SCIP_Real* flowcoverweight), /**< pointer to store weight of flow cover */
10330 SCIP_Real* lambda /**< pointer to store lambda */
10331 )
10332{
10333 int j;
10334 SCIP_Real QUAD(tmp);
10335
10336 assert(scip != NULL);
10337 assert(coefs != NULL);
10338 assert(vubcoefs != NULL);
10339 assert(solitems != NULL);
10340 assert(nonsolitems != NULL);
10341 assert(nsolitems >= 0);
10342 assert(nnonsolitems >= 0);
10343 assert(nflowcovervars != NULL && *nflowcovervars >= 0);
10344 assert(nnonflowcovervars != NULL && *nnonflowcovervars >= 0);
10345 assert(flowcoverstatus != NULL);
10346 assert(QUAD_HI(flowcoverweight) != NULL);
10347 assert(lambda != NULL);
10348
10349 /* get flowcover status for each item */
10350 for( j = 0; j < nsolitems; j++ )
10351 {
10352 /* j in N1 with z°_j = 1 => j in N1\C1 */
10353 if( coefs[solitems[j]] == 1 )
10354 {
10355 flowcoverstatus[solitems[j]] = -1;
10356 (*nnonflowcovervars)++;
10357 }
10358 /* j in N2 with z_j = 1 => j in C2 */
10359 else
10360 {
10361 assert(coefs[solitems[j]] == -1);
10362 flowcoverstatus[solitems[j]] = 1;
10363 (*nflowcovervars)++;
10364 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, -vubcoefs[solitems[j]]);
10365 }
10366 }
10367 for( j = 0; j < nnonsolitems; j++ )
10368 {
10369 /* j in N1 with z°_j = 0 => j in C1 */
10370 if( coefs[nonsolitems[j]] == 1 )
10371 {
10372 flowcoverstatus[nonsolitems[j]] = 1;
10373 (*nflowcovervars)++;
10374 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, vubcoefs[nonsolitems[j]]);
10375 }
10376 /* j in N2 with z_j = 0 => j in N2\C2 */
10377 else
10378 {
10379 assert(coefs[nonsolitems[j]] == -1);
10380 flowcoverstatus[nonsolitems[j]] = -1;
10381 (*nnonflowcovervars)++;
10382 }
10383 }
10384
10385 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
10386 SCIPquadprecSumQD(tmp, *flowcoverweight, -rhs);
10387 *lambda = QUAD_TO_DBL(tmp);
10388}
10389
10390#ifndef NO_EXACT_KNAPSACK
10391
10392/** checks whether the given scalar scales the given value to an integral number with error in the given bounds */
10393static
10395 SCIP_Real val, /**< value that should be scaled to an integral value */
10396 SCIP_Real scalar, /**< scalar that should be tried */
10397 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
10398 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
10399 )
10400{
10401 SCIP_Real sval;
10402 SCIP_Real downval;
10403 SCIP_Real upval;
10404
10405 assert(mindelta <= 0.0);
10406 assert(maxdelta >= 0.0);
10407
10408 sval = val * scalar;
10409 downval = floor(sval);
10410 upval = ceil(sval);
10411
10412 return (SCIPrelDiff(sval, downval) <= maxdelta || SCIPrelDiff(sval, upval) >= mindelta);
10413}
10414
10415/** get integral number with error in the bounds which corresponds to given value scaled by a given scalar;
10416 * should be used in connection with isIntegralScalar()
10417 */
10418static
10419SCIP_Longint getIntegralVal(
10420 SCIP_Real val, /**< value that should be scaled to an integral value */
10421 SCIP_Real scalar, /**< scalar that should be tried */
10422 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
10423 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
10424 )
10425{
10426 SCIP_Real sval;
10427 SCIP_Real upval;
10428 SCIP_Longint intval;
10429
10430 assert(mindelta <= 0.0);
10431 assert(maxdelta >= 0.0);
10432
10433 sval = val * scalar;
10434 upval = ceil(sval);
10435
10436 if( SCIPrelDiff(sval, upval) >= mindelta )
10437 intval = (SCIP_Longint) upval;
10438 else
10439 intval = (SCIP_Longint) (floor(sval));
10440
10441 return intval;
10442}
10443
10444/** get a flow cover (C1, C2) for a given 0-1 single node flow set
10445 * {(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},
10446 * 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
10447 */
10448static
10450 SCIP* scip, /**< SCIP data structure */
10451 SNF_RELAXATION* snf, /**< the single node flow relaxation */
10452 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
10453 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
10454 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
10455 SCIP_Real* lambda, /**< pointer to store lambda */
10456 SCIP_Bool* found /**< pointer to store whether a cover was found */
10457 )
10458{
10459 SCIP_Real* transprofitsint;
10460 SCIP_Real* transprofitsreal;
10461 SCIP_Real* transweightsreal;
10462 SCIP_Longint* transweightsint;
10463 int* items;
10464 int* itemsint;
10465 int* nonsolitems;
10466 int* solitems;
10467 SCIP_Real QUAD(flowcoverweight);
10468 SCIP_Real QUAD(flowcoverweightafterfix);
10469 SCIP_Real n1itemsweight;
10470 SCIP_Real n2itemsminweight;
10471 SCIP_Real scalar;
10472 SCIP_Real transcapacityreal;
10473#if !defined(NDEBUG) || defined(SCIP_DEBUG)
10474 SCIP_Bool kpexact;
10475#endif
10476 SCIP_Bool scalesuccess;
10477 SCIP_Bool transweightsrealintegral;
10478 SCIP_Longint transcapacityint;
10479 int nflowcovervarsafterfix;
10480 int nitems;
10481 int nn1items;
10482 int nnonflowcovervarsafterfix;
10483 int nnonsolitems;
10484 int nsolitems;
10485 int j;
10486
10487 assert(scip != NULL);
10488 assert(snf->transvarcoefs != NULL);
10489 assert(snf->transbinvarsolvals != NULL);
10490 assert(snf->transvarvubcoefs != NULL);
10491 assert(snf->ntransvars > 0);
10492 assert(nflowcovervars != NULL);
10493 assert(nnonflowcovervars != NULL);
10494 assert(flowcoverstatus != NULL);
10495 assert(lambda != NULL);
10496 assert(found != NULL);
10497
10498 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
10499
10500 /* get data structures */
10502 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
10503 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
10504 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsint, snf->ntransvars) );
10505 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
10506 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
10507 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
10508 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
10509
10510 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
10511 *found = FALSE;
10512 *nflowcovervars = 0;
10513 *nnonflowcovervars = 0;
10514
10515 QUAD_ASSIGN(flowcoverweight, 0.0);
10516 nflowcovervarsafterfix = 0;
10517 nnonflowcovervarsafterfix = 0;
10518 QUAD_ASSIGN(flowcoverweightafterfix, 0.0);
10519#if !defined(NDEBUG) || defined(SCIP_DEBUG)
10520 kpexact = FALSE;
10521#endif
10522
10523 /* fix some variables in advance according to the following fixing strategy
10524 * put j into N1\C1, if j in N1 and x*_j = 0,
10525 * put j into C1, if j in N1 and x*_j = 1,
10526 * put j into C2, if j in N2 and x*_j = 1,
10527 * put j into N2\C2, if j in N2 and x*_j = 0
10528 * and get the set of the remaining variables
10529 */
10530 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
10531 nitems = 0;
10532 nn1items = 0;
10533 n1itemsweight = 0.0;
10534 n2itemsminweight = SCIP_REAL_MAX;
10535 for( j = 0; j < snf->ntransvars; j++ )
10536 {
10537 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
10538 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
10539 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
10540
10541 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
10542 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
10543 {
10544 flowcoverstatus[j] = -1;
10545 (*nnonflowcovervars)++;
10546 continue;
10547 }
10548
10549 /* x*_j is fractional */
10551 {
10552 items[nitems] = j;
10553 nitems++;
10554 if( snf->transvarcoefs[j] == 1 )
10555 {
10556 n1itemsweight += snf->transvarvubcoefs[j];
10557 nn1items++;
10558 }
10559 else
10560 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
10561 }
10562 /* j is in N1 and x*_j = 0 */
10563 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
10564 {
10565 flowcoverstatus[j] = -1;
10566 (*nnonflowcovervars)++;
10567 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
10568 }
10569 /* j is in N1 and x*_j = 1 */
10570 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
10571 {
10572 flowcoverstatus[j] = 1;
10573 (*nflowcovervars)++;
10574 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
10575 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
10576 }
10577 /* j is in N2 and x*_j = 1 */
10578 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
10579 {
10580 flowcoverstatus[j] = 1;
10581 (*nflowcovervars)++;
10582 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
10583 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
10584 }
10585 /* j is in N2 and x*_j = 0 */
10586 else
10587 {
10588 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
10589 flowcoverstatus[j] = -1;
10590 (*nnonflowcovervars)++;
10591 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
10592 }
10593 }
10594 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
10595 assert(nn1items >= 0);
10596
10597 /* to find a flow cover, transform the following knapsack problem
10598 *
10599 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
10600 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
10601 * z_j in {0,1} for all j in N1 & N2
10602 *
10603 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
10604 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
10605 *
10606 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
10607 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
10608 * z°_j in {0,1} for all j in N1
10609 * z_j in {0,1} for all j in N2,
10610 * and solve it approximately under consideration of the fixing,
10611 * or
10612 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
10613 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
10614 * and multiplying the constraint by a suitable scalar C
10615 *
10616 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
10617 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
10618 * z°_j in {0,1} for all j in N1
10619 * z_j in {0,1} for all j in N2,
10620 * where
10621 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
10622 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
10623 * and solve it exactly under consideration of the fixing.
10624 */
10625 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
10626
10627 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
10628 transweightsrealintegral = TRUE;
10629 for( j = 0; j < nitems; j++ )
10630 {
10631 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
10632
10633 if( !isIntegralScalar(transweightsreal[j], 1.0, -MINDELTA, MAXDELTA) )
10634 transweightsrealintegral = FALSE;
10635
10636 if( snf->transvarcoefs[items[j]] == 1 )
10637 {
10638 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
10639 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
10640 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
10641 }
10642 else
10643 {
10644 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
10645 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
10646 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
10647 }
10648 }
10649 /* get capacity of knapsack constraint in KP^SNF_rat */
10650 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight;
10651 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
10652 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
10653
10654 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
10655 * is less than or equal to zero
10656 */
10657 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
10658 {
10659 assert(!(*found));
10660 goto TERMINATE;
10661 }
10662
10663 /* KP^SNF_rat has been solved by fixing some variables in advance */
10664 assert(nitems >= 0);
10665 if( nitems == 0)
10666 {
10667 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
10668 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
10669 *lambda = QUAD_TO_DBL(flowcoverweight);
10670 *found = TRUE;
10671 goto TERMINATE;
10672 }
10673
10674 /* Use the following strategy
10675 * solve KP^SNF_int exactly, if a suitable factor C is found and (nitems*capacity) <= MAXDYNPROGSPACE,
10676 * solve KP^SNF_rat approximately, otherwise
10677 */
10678
10679 /* find a scaling factor C */
10680 if( transweightsrealintegral )
10681 {
10682 /* weights are already integral */
10683 scalar = 1.0;
10684 scalesuccess = TRUE;
10685 }
10686 else
10687 {
10688 scalesuccess = FALSE;
10689 SCIP_CALL( SCIPcalcIntegralScalar(transweightsreal, nitems, -MINDELTA, MAXDELTA, MAXDNOM, MAXSCALE, &scalar,
10690 &scalesuccess) );
10691 }
10692
10693 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
10694 nsolitems = -1;
10695 nnonsolitems = -1;
10696
10697 /* suitable factor C was found*/
10698 if( scalesuccess )
10699 {
10700 SCIP_Real tmp1;
10701 SCIP_Real tmp2;
10702
10703 /* transform KP^SNF to KP^SNF_int */
10704 for( j = 0; j < nitems; ++j )
10705 {
10706 transweightsint[j] = getIntegralVal(transweightsreal[j], scalar, -MINDELTA, MAXDELTA);
10707 transprofitsint[j] = transprofitsreal[j];
10708 itemsint[j] = items[j];
10709 }
10710 if( isIntegralScalar(transcapacityreal, scalar, -MINDELTA, MAXDELTA) )
10711 {
10712 transcapacityint = getIntegralVal(transcapacityreal, scalar, -MINDELTA, MAXDELTA);
10713 transcapacityint -= 1;
10714 }
10715 else
10716 transcapacityint = (SCIP_Longint) (transcapacityreal * scalar);
10717 nflowcovervarsafterfix = *nflowcovervars;
10718 nnonflowcovervarsafterfix = *nnonflowcovervars;
10719 QUAD_ASSIGN_Q(flowcoverweightafterfix, flowcoverweight);
10720
10721 tmp1 = (SCIP_Real) (nitems + 1);
10722 tmp2 = (SCIP_Real) ((transcapacityint) + 1);
10723 if( transcapacityint * nitems <= MAXDYNPROGSPACE && tmp1 * tmp2 <= INT_MAX / 8.0)
10724 {
10725 SCIP_Bool success;
10726
10727 /* solve KP^SNF_int by dynamic programming */
10728 SCIP_CALL( SCIPsolveKnapsackExactly(scip, nitems, transweightsint, transprofitsint, transcapacityint,
10729 itemsint, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL, &success) );
10730
10731 if( !success )
10732 {
10733 /* solve KP^SNF_rat approximately */
10734 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal,
10735 transcapacityreal, items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
10736 }
10737#if !defined(NDEBUG) || defined(SCIP_DEBUG)
10738 else
10739 kpexact = TRUE;
10740#endif
10741 }
10742 else
10743 {
10744 /* solve KP^SNF_rat approximately */
10745 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
10746 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
10747 assert(!kpexact);
10748 }
10749 }
10750 else
10751 {
10752 /* solve KP^SNF_rat approximately */
10753 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
10754 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
10755 assert(!kpexact);
10756 }
10757
10758 assert(nsolitems != -1);
10759 assert(nnonsolitems != -1);
10760
10761 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
10762 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
10763 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
10764 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
10765 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
10766
10767 /* if the found structure is not a flow cover, because of scaling, solve KP^SNF_rat approximately */
10768 if( SCIPisFeasLE(scip, *lambda, 0.0) )
10769 {
10770 assert(kpexact);
10771
10772 /* solve KP^SNF_rat approximately */
10773 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
10774 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
10775#ifdef SCIP_DEBUG /* this time only for SCIP_DEBUG, because only then, the variable is used again */
10776 kpexact = FALSE;
10777#endif
10778
10779 /* build the flow cover from the solution of KP^SNF_rat and the fixing */
10780 *nflowcovervars = nflowcovervarsafterfix;
10781 *nnonflowcovervars = nnonflowcovervarsafterfix;
10782 QUAD_ASSIGN_Q(flowcoverweight, flowcoverweightafterfix);
10783
10784 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
10785 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
10786 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
10787 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
10788 }
10789 *found = SCIPisFeasGT(scip, *lambda, 0.0);
10790
10791 TERMINATE:
10792 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
10793#ifdef SCIP_DEBUG
10794 if( *found )
10795 {
10796 SCIPdebugMsg(scip, "2. %s solution:\n", kpexact ? "exact" : "approximate");
10797 for( j = 0; j < snf->ntransvars; j++ )
10798 {
10799 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
10800 {
10801 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
10802 }
10803 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
10804 {
10805 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
10806 }
10807 }
10808 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
10809 }
10810#endif
10811
10812 /* free data structures */
10813 SCIPfreeBufferArray(scip, &nonsolitems);
10814 SCIPfreeBufferArray(scip, &solitems);
10815 SCIPfreeBufferArray(scip, &transweightsint);
10816 SCIPfreeBufferArray(scip, &transweightsreal);
10817 SCIPfreeBufferArray(scip, &transprofitsint);
10818 SCIPfreeBufferArray(scip, &transprofitsreal);
10819 SCIPfreeBufferArray(scip, &itemsint);
10820 SCIPfreeBufferArray(scip, &items);
10821
10822 return SCIP_OKAY;
10823}
10824
10825#else
10826
10827/** get a flow cover \f$(C1, C2)\f$ for a given 0-1 single node flow set
10828 * \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$,
10829 * i.e., get sets \f$ C1 \subset N1 \f$ and \f$ C2 \subset N2 \f$ with
10830 * \f$ \sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda \f$ and \f$ lambda > 0 \f$
10831 */
10832static
10834 SCIP* scip, /**< SCIP data structure */
10835 SNF_RELAXATION* snf, /**< the 0-1 single node flow relaxation */
10836 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
10837 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
10838 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
10839 SCIP_Real* lambda, /**< pointer to store lambda */
10840 SCIP_Bool* found /**< pointer to store whether a cover was found */
10841 )
10842{
10843 SCIP_Real* transprofitsreal;
10844 SCIP_Real* transweightsreal;
10845 SCIP_Longint* transweightsint;
10846 int* items;
10847 int* itemsint;
10848 int* nonsolitems;
10849 int* solitems;
10850 SCIP_Real QUAD(flowcoverweight);
10851 SCIP_Real n1itemsweight;
10852 SCIP_Real n2itemsminweight;
10853 SCIP_Real transcapacityreal;
10854 int nitems;
10855#ifndef NDEBUG
10856 int nn1items = 0;
10857#endif
10858 int nnonsolitems;
10859 int nsolitems;
10860 int j;
10861
10862 assert(scip != NULL);
10863 assert(snf->transvarcoefs != NULL);
10864 assert(snf->transbinvarsolvals != NULL);
10865 assert(snf->transvarvubcoefs != NULL);
10866 assert(snf->ntransvars > 0);
10867 assert(nflowcovervars != NULL);
10868 assert(nnonflowcovervars != NULL);
10869 assert(flowcoverstatus != NULL);
10870 assert(lambda != NULL);
10871 assert(found != NULL);
10872
10873 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
10874
10875 /* get data structures */
10877 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
10878 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
10879 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
10880 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
10881 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
10882 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
10883
10884 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
10885 *found = FALSE;
10886 *nflowcovervars = 0;
10887 *nnonflowcovervars = 0;
10888
10889 QUAD_ASSIGN(flowcoverweight, 0.0);
10890
10891 /* fix some variables in advance according to the following fixing strategy
10892 * put j into N1\C1, if j in N1 and x*_j = 0,
10893 * put j into C1, if j in N1 and x*_j = 1,
10894 * put j into C2, if j in N2 and x*_j = 1,
10895 * put j into N2\C2, if j in N2 and x*_j = 0
10896 * and get the set of the remaining variables
10897 */
10898 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
10899 nitems = 0;
10900 n1itemsweight = 0.0;
10901 n2itemsminweight = SCIP_REAL_MAX;
10902 for( j = 0; j < snf->ntransvars; j++ )
10903 {
10904 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
10905 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
10906 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
10907
10908 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
10909 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
10910 {
10911 flowcoverstatus[j] = -1;
10912 (*nnonflowcovervars)++;
10913 continue;
10914 }
10915
10916 /* x*_j is fractional */
10918 {
10919 items[nitems] = j;
10920 nitems++;
10921 if( snf->transvarcoefs[j] == 1 )
10922 {
10923 n1itemsweight += snf->transvarvubcoefs[j];
10924#ifndef NDEBUG
10925 nn1items++;
10926#endif
10927 }
10928 else
10929 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
10930 }
10931 /* j is in N1 and x*_j = 0 */
10932 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
10933 {
10934 flowcoverstatus[j] = -1;
10935 (*nnonflowcovervars)++;
10936 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
10937 }
10938 /* j is in N1 and x*_j = 1 */
10939 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
10940 {
10941 flowcoverstatus[j] = 1;
10942 (*nflowcovervars)++;
10943 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
10944 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
10945 }
10946 /* j is in N2 and x*_j = 1 */
10947 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
10948 {
10949 flowcoverstatus[j] = 1;
10950 (*nflowcovervars)++;
10951 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
10952 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
10953 }
10954 /* j is in N2 and x*_j = 0 */
10955 else
10956 {
10957 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
10958 flowcoverstatus[j] = -1;
10959 (*nnonflowcovervars)++;
10960 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
10961 }
10962 }
10963 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
10964 assert(nn1items >= 0);
10965
10966 /* to find a flow cover, transform the following knapsack problem
10967 *
10968 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
10969 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
10970 * z_j in {0,1} for all j in N1 & N2
10971 *
10972 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
10973 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
10974 *
10975 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
10976 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
10977 * z°_j in {0,1} for all j in N1
10978 * z_j in {0,1} for all j in N2,
10979 * and solve it approximately under consideration of the fixing,
10980 * or
10981 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
10982 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
10983 * and multiplying the constraint by a suitable scalar C
10984 *
10985 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
10986 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
10987 * z°_j in {0,1} for all j in N1
10988 * z_j in {0,1} for all j in N2,
10989 * where
10990 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
10991 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
10992 * and solve it exactly under consideration of the fixing.
10993 */
10994 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
10995
10996 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
10997 for( j = 0; j < nitems; j++ )
10998 {
10999 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
11000
11001 if( snf->transvarcoefs[items[j]] == 1 )
11002 {
11003 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
11004 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
11005 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
11006 }
11007 else
11008 {
11009 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
11010 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
11011 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
11012 }
11013 }
11014 /* get capacity of knapsack constraint in KP^SNF_rat */
11015 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight; /*lint !e644*/
11016 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
11017 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
11018
11019 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
11020 * is less than or equal to zero
11021 */
11022 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
11023 {
11024 assert(!(*found));
11025 goto TERMINATE;
11026 }
11027
11028 /* KP^SNF_rat has been solved by fixing some variables in advance */
11029 assert(nitems >= 0);
11030 if( nitems == 0 )
11031 {
11032 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
11033 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
11034 *lambda = QUAD_TO_DBL(flowcoverweight);
11035 *found = TRUE;
11036 goto TERMINATE;
11037 }
11038
11039 /* Solve the KP^SNF_rat approximately */
11040
11041 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
11042 nsolitems = -1;
11043 nnonsolitems = -1;
11044
11045 /* suitable factor C was found*/
11046 /* solve KP^SNF_rat approximately */
11047 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
11048 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
11049
11050 assert(nsolitems != -1);
11051 assert(nnonsolitems != -1);
11052
11053 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
11054 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
11055 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
11056 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
11057 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
11058
11059 *found = SCIPisFeasGT(scip, *lambda, 0.0);
11060
11061 TERMINATE:
11062 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
11063#ifdef SCIP_DEBUG
11064 if( *found )
11065 {
11066 SCIPdebugMsg(scip, "2. approximate solution:\n");
11067 for( j = 0; j < snf->ntransvars; j++ )
11068 {
11069 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
11070 {
11071 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
11072 }
11073 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
11074 {
11075 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
11076 }
11077 }
11078 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
11079 }
11080#endif
11081
11082 /* free data structures */
11083 SCIPfreeBufferArray(scip, &nonsolitems);
11084 SCIPfreeBufferArray(scip, &solitems);
11085 SCIPfreeBufferArray(scip, &transweightsint);
11086 SCIPfreeBufferArray(scip, &transweightsreal);
11087 SCIPfreeBufferArray(scip, &transprofitsreal);
11088 SCIPfreeBufferArray(scip, &itemsint);
11089 SCIPfreeBufferArray(scip, &items);
11090
11091 return SCIP_OKAY;
11092}
11093
11094#endif
11095
11096/** evaluate the super-additive lifting function for the lifted simple generalized flowcover inequalities
11097 * for a given value \f$ x \in \{ u_j \mid j \in C- \} \f$.
11098 */
11099static
11101 SCIP* scip, /**< SCIP data structure */
11102 LIFTINGDATA* liftingdata, /**< lifting data to use */
11103 SCIP_Real x /**< value where to evaluate lifting function */
11104 )
11105{
11106 SCIP_Real QUAD(tmp);
11107 SCIP_Real xpluslambda;
11108 int i;
11109
11110 assert( liftingdata != NULL );
11111
11112 xpluslambda = x + liftingdata->lambda;
11113
11114 i = 0;
11115 while( i < liftingdata->r && SCIPisGT(scip, xpluslambda, liftingdata->M[i+1]) )
11116 ++i;
11117
11118 if( i < liftingdata->t )
11119 {
11120 if( SCIPisLE(scip, liftingdata->M[i], x) )
11121 {
11122 assert(SCIPisLE(scip, xpluslambda, liftingdata->M[i+1]));
11123 return i * liftingdata->lambda;
11124 }
11125
11126 assert(i > 0 && SCIPisLE(scip, liftingdata->M[i], xpluslambda) && x <= liftingdata->M[i]);
11127
11128 /* return x - liftingdata->M[i] + i * liftingdata->lambda */
11129 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
11130 SCIPquadprecSumQD(tmp, tmp, x);
11131 SCIPquadprecSumQD(tmp, tmp, -liftingdata->M[i]);
11132 return QUAD_TO_DBL(tmp);
11133 }
11134
11135 if( i < liftingdata->r )
11136 {
11137 assert(!SCIPisInfinity(scip, liftingdata->mp));
11138
11139 /* p = liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml; */
11140 SCIPquadprecSumDD(tmp, liftingdata->m[i], -liftingdata->mp);
11141 SCIPquadprecSumQD(tmp, tmp, -liftingdata->ml);
11142 SCIPquadprecSumQD(tmp, tmp, liftingdata->lambda);
11143
11144 /* p = MAX(0.0, p); */
11145 if( QUAD_HI(tmp) < 0.0 )
11146 {
11147 QUAD_ASSIGN(tmp, 0.0);
11148 }
11149
11150 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
11151 SCIPquadprecSumQD(tmp, tmp, liftingdata->ml);
11152
11153 if( SCIPisLT(scip, QUAD_TO_DBL(tmp), xpluslambda) )
11154 return i * liftingdata->lambda;
11155
11156 assert(SCIPisFeasLE(scip, liftingdata->M[i], xpluslambda) &&
11157 SCIPisFeasLE(scip, xpluslambda, liftingdata->M[i] + liftingdata->ml +
11158 MAX(0.0, liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml)));
11159
11160 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
11161 SCIPquadprecSumQD(tmp, tmp, x);
11162 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[i]);
11163 return QUAD_TO_DBL(tmp);
11164 }
11165
11166 assert(i == liftingdata->r && SCIPisLE(scip, liftingdata->M[liftingdata->r], xpluslambda));
11167
11168 SCIPquadprecProdDD(tmp, liftingdata->r, liftingdata->lambda);
11169 SCIPquadprecSumQD(tmp, tmp, x);
11170 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[liftingdata->r]);
11171 return QUAD_TO_DBL(tmp);
11172}
11173
11174/** computes
11175 * \f[
11176 * (\alpha_j, \beta_j) =
11177 * \begin{cases}
11178 * (0, 0) &\quad\text{if} M_i \leq u_j \leq M_{i+1} - \lambda \\
11179 * (1, M_i - i \lambda) &\quad\text{if} M_i − \lambda < u_j < M_i \\
11180 * \end{cases}
11181 * \f]
11182 */
11183static
11185 SCIP* scip, /**< SCIP data structure */
11186 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
11187 SCIP_Real vubcoef, /**< vub coefficient to get alpha and beta for */
11188 int* alpha, /**< get alpha coefficient for lifting */
11189 SCIP_Real* beta /**< get beta coefficient for lifting */
11190 )
11191{
11192 SCIP_Real vubcoefpluslambda;
11193 int i;
11194
11195 vubcoefpluslambda = vubcoef + liftingdata->lambda;
11196
11197 i = 0;
11198 while( i < liftingdata->r && SCIPisGT(scip, vubcoefpluslambda, liftingdata->M[i+1]) )
11199 ++i;
11200
11201 if( SCIPisLT(scip, vubcoef, liftingdata->M[i]) )
11202 {
11203 SCIP_Real QUAD(tmp);
11204 assert(liftingdata->M[i] < vubcoefpluslambda);
11205 *alpha = 1;
11206 SCIPquadprecProdDD(tmp, -i, liftingdata->lambda);
11207 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
11208 *beta = QUAD_TO_DBL(tmp);
11209 }
11210 else
11211 {
11212 assert(SCIPisSumLE(scip, liftingdata->M[i], vubcoef));
11213 assert(i == liftingdata->r || SCIPisLE(scip, vubcoefpluslambda, liftingdata->M[i+1]));
11214 *alpha = 0;
11215 *beta = 0.0;
11216 }
11217}
11218
11219/** compute relevant data for performing the sequence independent lifting */
11220static
11222 SCIP* scip, /**< SCIP data structure */
11223 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
11224 int* transvarflowcoverstatus, /**< pointer to store whether non-binary var is in L2 (2) or not (-1 or 1) */
11225 SCIP_Real lambda, /**< lambda */
11226 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
11227 SCIP_Bool* valid /**< is the lifting data valid */
11228 )
11229{
11230 int i;
11231 SCIP_Real QUAD(tmp);
11232 SCIP_Real QUAD(sumN2mC2LE);
11233 SCIP_Real QUAD(sumN2mC2GT);
11234 SCIP_Real QUAD(sumC1LE);
11235 SCIP_Real QUAD(sumC2);
11236
11237#ifndef NDEBUG
11238 /* for debugging */
11239 liftingdata->m = NULL;
11240 liftingdata->M = NULL;
11241 liftingdata->lambda = SCIP_INVALID;
11242 liftingdata->t = 0;
11243 liftingdata->mp = SCIP_INVALID;
11244#endif
11245
11246 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->m, snf->ntransvars) );
11247
11248 liftingdata->r = 0;
11249 QUAD_ASSIGN(sumN2mC2LE, 0.0);
11250 QUAD_ASSIGN(sumC1LE, 0.0);
11251 QUAD_ASSIGN(sumN2mC2GT, 0.0);
11252 QUAD_ASSIGN(sumC2, 0.0);
11253
11254 liftingdata->mp = SCIPinfinity(scip);
11255
11256 *valid = FALSE;
11257
11258 for( i = 0; i < snf->ntransvars; ++i )
11259 {
11260 int s = (snf->transvarcoefs[i] + 1) + (transvarflowcoverstatus[i] + 1)/2;
11261
11262 switch(s)
11263 {
11264 case 0: /* var is in N2 \ C2 */
11265 assert(snf->transvarvubcoefs[i] >= 0.0);
11266 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == -1);
11267
11268 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
11269 {
11270 SCIPquadprecSumQD(sumN2mC2GT, sumN2mC2GT, snf->transvarvubcoefs[i]);
11271 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
11272 }
11273 else
11274 {
11275 SCIPquadprecSumQD(sumN2mC2LE, sumN2mC2LE, snf->transvarvubcoefs[i]);
11276 }
11277 break;
11278 case 1: /* var is in C2 */
11279 assert(snf->transvarvubcoefs[i] > 0.0);
11280 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == 1);
11281
11282 SCIPquadprecSumQD(sumC2, sumC2, snf->transvarvubcoefs[i]);
11283 break;
11284 case 3: /* var is in C1 */
11285 assert(snf->transvarcoefs[i] == 1 && transvarflowcoverstatus[i] == 1);
11286 assert(snf->transvarvubcoefs[i] > 0.0);
11287
11288 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
11289 {
11290 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
11291 liftingdata->mp = MIN(liftingdata->mp, snf->transvarvubcoefs[i]);
11292 }
11293 else
11294 {
11295 SCIPquadprecSumQD(sumC1LE, sumC1LE, snf->transvarvubcoefs[i]);
11296 }
11297 break;
11298 default:
11299 assert(s == 2);
11300 continue;
11301 }
11302 }
11303
11304 if( SCIPisInfinity(scip, liftingdata->mp) )
11305 {
11306 SCIPfreeBufferArray(scip, &liftingdata->m);
11307 return SCIP_OKAY;
11308 }
11309
11310 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->M, liftingdata->r + 1) );
11311
11312 *valid = TRUE;
11313
11314 SCIPquadprecSumQQ(tmp, sumC1LE, sumN2mC2LE);
11315 liftingdata->ml = MIN(lambda, QUAD_TO_DBL(tmp));
11316 SCIPquadprecSumQD(tmp, sumC2, snf->transrhs);
11317 liftingdata->d1 = QUAD_TO_DBL(tmp);
11318 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2GT);
11319 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2LE);
11320 liftingdata->d2 = QUAD_TO_DBL(tmp);
11321
11322 SCIPsortDownReal(liftingdata->m, liftingdata->r);
11323
11324 /* compute M[i] = sum_{i \in [1,r]} m[i] where m[*] is sorted decreasingly and M[0] = 0 */
11325 QUAD_ASSIGN(tmp, 0.0);
11326 for( i = 0; i < liftingdata->r; ++i)
11327 {
11328 liftingdata->M[i] = QUAD_TO_DBL(tmp);
11329 SCIPquadprecSumQD(tmp, tmp, liftingdata->m[i]);
11330 }
11331
11332 liftingdata->M[liftingdata->r] = QUAD_TO_DBL(tmp);
11333
11334 SCIP_UNUSED( SCIPsortedvecFindDownReal(liftingdata->m, liftingdata->mp, liftingdata->r, &liftingdata->t) );
11335 assert(liftingdata->m[liftingdata->t] == liftingdata->mp || SCIPisInfinity(scip, liftingdata->mp)); /*lint !e777*/
11336
11337 /* compute t largest index sucht that m_t = mp
11338 * note that liftingdata->m[t-1] == mp due to zero based indexing of liftingdata->m
11339 */
11340 ++liftingdata->t;
11341 while( liftingdata->t < liftingdata->r && liftingdata->m[liftingdata->t] == liftingdata->mp ) /*lint !e777*/
11342 ++liftingdata->t;
11343
11344 liftingdata->lambda = lambda;
11345
11346 return SCIP_OKAY;
11347}
11348
11349/** destroy data used for the sequence independent lifting */
11350static
11352 SCIP* scip, /**< SCIP data structure */
11353 LIFTINGDATA* liftingdata /**< pointer to lifting function struct */
11354 )
11355{
11356 SCIPfreeBufferArray(scip, &liftingdata->M);
11357 SCIPfreeBufferArray(scip, &liftingdata->m);
11358}
11359
11360/** store the simple lifted flowcover cut defined by the given data in the given arrays
11361 * the array for storing the cut coefficients must be all zeros
11362 */
11363static
11365 SCIP* scip, /**< SCIP data structure */
11366 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
11367 SCIP_AGGRROW* aggrrow, /**< aggrrow used to construct SNF relaxation */
11368 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
11369 SCIP_Real lambda, /**< lambda */
11370 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
11371 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
11372 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
11373 int* nnz, /**< number of non-zeros in cut */
11374 SCIP_Bool* success /**< was the cut successfully generated */
11375 )
11376{
11377 SCIP_Real QUAD(rhs);
11378 LIFTINGDATA liftingdata;
11379 int i;
11380
11381 SCIP_CALL( computeLiftingData(scip, snf, flowcoverstatus, lambda, &liftingdata, success) );
11382 if( ! *success )
11383 return SCIP_OKAY;
11384 assert( liftingdata.m != NULL );
11385 assert( liftingdata.M != NULL );
11386 assert( liftingdata.lambda != SCIP_INVALID ); /*lint !e777*/
11387 assert( liftingdata.r >= 0 );
11388 assert( liftingdata.t >= 0 );
11389 assert( liftingdata.mp != SCIP_INVALID ); /*lint !e777*/
11390
11391 QUAD_ASSIGN(rhs, liftingdata.d1);
11392
11393 *nnz = 0;
11394
11395 for( i = 0; i < snf->ntransvars; ++i )
11396 {
11397 int s = (snf->transvarcoefs[i] + 1) + (flowcoverstatus[i] + 1)/2;
11398
11399 switch(s)
11400 {
11401 case 0: /* var is in N2 \ C2 */
11402 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
11403 {
11404 /* var is in L- */
11405 if( snf->origbinvars[i] != -1 )
11406 {
11407 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11408 cutinds[*nnz] = snf->origbinvars[i];
11409 cutcoefs[snf->origbinvars[i]] = -lambda;
11410 ++(*nnz);
11411 }
11412 else
11413 {
11414 SCIPquadprecSumQD(rhs, rhs, lambda);
11415 }
11416 }
11417 else
11418 {
11419 /* var is in L-- */
11420 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
11421 {
11422 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
11423 cutinds[*nnz] = snf->origcontvars[i];
11424 cutcoefs[snf->origcontvars[i]] = -snf->aggrcoefscont[i];
11425 ++(*nnz);
11426 }
11427
11428 if( snf->origbinvars[i] != -1 && snf->aggrcoefsbin[i] != 0.0 )
11429 {
11430 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11431 cutinds[*nnz] = snf->origbinvars[i];
11432 cutcoefs[snf->origbinvars[i]] = -snf->aggrcoefsbin[i];
11433 ++(*nnz);
11434 }
11435
11436 SCIPquadprecSumQD(rhs, rhs, snf->aggrconstants[i]);
11437 }
11438 break;
11439 case 1: /* var is in C2 */
11440 {
11441 assert(snf->transvarvubcoefs[i] > 0.0);
11442 assert(snf->transvarcoefs[i] == -1 && flowcoverstatus[i] == 1);
11443
11444 if( snf->origbinvars[i] != -1 )
11445 {
11446 SCIP_Real liftedbincoef = evaluateLiftingFunction(scip, &liftingdata, snf->transvarvubcoefs[i]);
11447 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11448 if( liftedbincoef != 0.0 )
11449 {
11450 cutinds[*nnz] = snf->origbinvars[i];
11451 cutcoefs[snf->origbinvars[i]] = -liftedbincoef;
11452 ++(*nnz);
11453 SCIPquadprecSumQD(rhs, rhs, -liftedbincoef);
11454 }
11455 }
11456 break;
11457 }
11458 case 2: /* var is in N1 \ C1 */
11459 {
11460 int alpha;
11461 SCIP_Real beta;
11462
11463 assert(snf->transvarcoefs[i] == 1 && flowcoverstatus[i] == -1);
11464
11465 getAlphaAndBeta(scip, &liftingdata, snf->transvarvubcoefs[i], &alpha, &beta);
11466 assert(alpha == 0 || alpha == 1);
11467
11468 if( alpha == 1 )
11469 {
11470 SCIP_Real QUAD(binvarcoef);
11471 assert(beta > 0.0);
11472
11473 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
11474 {
11475 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
11476 cutinds[*nnz] = snf->origcontvars[i];
11477 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
11478 ++(*nnz);
11479 }
11480
11481 SCIPquadprecSumDD(binvarcoef, snf->aggrcoefsbin[i], -beta);
11482 if( snf->origbinvars[i] != -1 )
11483 {
11484 SCIP_Real tmp;
11485
11486 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11487
11488 tmp = QUAD_TO_DBL(binvarcoef);
11489 if( tmp != 0.0 )
11490 {
11491 cutinds[*nnz] = snf->origbinvars[i];
11492 cutcoefs[snf->origbinvars[i]] = tmp;
11493 ++(*nnz);
11494 }
11495 }
11496 else
11497 {
11498 SCIPquadprecSumQQ(rhs, rhs, -binvarcoef);
11499 }
11500
11501 SCIPquadprecSumQD(rhs, rhs, -snf->aggrconstants[i]);
11502 }
11503 break;
11504 }
11505 case 3: /* var is in C1 */
11506 {
11507 SCIP_Real bincoef = snf->aggrcoefsbin[i];
11508 SCIP_Real constant = snf->aggrconstants[i];
11509
11510 if( snf->origbinvars[i] != -1 && SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
11511 {
11512 /* var is in C++ */
11513 SCIP_Real QUAD(tmp);
11514 SCIP_Real QUAD(tmp2);
11515
11516 SCIPquadprecSumDD(tmp, snf->transvarvubcoefs[i], -lambda);
11517
11518 SCIPquadprecSumQD(tmp2, tmp, constant);
11519 constant = QUAD_TO_DBL(tmp2);
11520
11521 SCIPquadprecSumQD(tmp2, tmp, -bincoef);
11522 bincoef = -QUAD_TO_DBL(tmp2);
11523 }
11524
11525 if( snf->origbinvars[i] != -1 && bincoef != 0.0 )
11526 {
11527 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
11528 cutinds[*nnz] = snf->origbinvars[i];
11529 cutcoefs[snf->origbinvars[i]] = bincoef;
11530 ++(*nnz);
11531 }
11532
11533 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
11534 {
11535 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
11536 cutinds[*nnz] = snf->origcontvars[i];
11537 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
11538 ++(*nnz);
11539 }
11540
11541 SCIPquadprecSumQD(rhs, rhs, -constant);
11542 break;
11543 }
11544 default:
11545 SCIPABORT();
11546 }
11547 }
11548
11549 destroyLiftingData(scip, &liftingdata);
11550
11551 {
11552 SCIP_ROW** rows = SCIPgetLPRows(scip);
11553 for( i = 0; i < aggrrow->nrows; ++i )
11554 {
11555 SCIP_ROW* row;
11556 SCIP_Real rowlhs;
11557 SCIP_Real rowrhs;
11558 SCIP_Real slackub;
11559 SCIP_Real slackcoef;
11560
11561 slackcoef = aggrrow->rowweights[i] * aggrrow->slacksign[i];
11562 assert(slackcoef != 0.0);
11563
11564 /* positive slack was implicitly handled in flow cover separation */
11565 if( slackcoef > 0.0 )
11566 continue;
11567
11568 row = rows[aggrrow->rowsinds[i]];
11569
11570 /* add the slack's definition multiplied with its coefficient to the cut */
11571 SCIP_CALL( varVecAddScaledRowCoefs(cutinds, cutcoefs, nnz, row, -aggrrow->rowweights[i]) );
11572
11573 /* retrieve sides of row */
11574 rowlhs = row->lhs - row->constant;
11575 rowrhs = row->rhs - row->constant;
11576
11577 if( row->integral )
11578 {
11579 rowrhs = SCIPfloor(scip, rowrhs);
11580 rowlhs = SCIPceil(scip, rowlhs);
11581 }
11582
11583 slackub = rowrhs - rowlhs;
11584
11585 /* move slack's constant to the right hand side, and add lambda to the right hand side if the
11586 * upper bound of the slack is larger than lambda, since then an artifical binary variable
11587 * for the slack would get coefficient -lambda
11588 */
11589 if( aggrrow->slacksign[i] == +1 )
11590 {
11591 SCIP_Real rhsslack;
11592 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
11593 assert(!SCIPisInfinity(scip, row->rhs));
11594
11595 rhsslack = rowrhs - SCIPgetRowMinActivity(scip, row);
11596 slackub = -aggrrow->rowweights[i] * MIN(rhsslack, slackub);
11597
11598 if( SCIPisGE(scip, slackub, lambda) )
11599 SCIPquadprecSumQD(rhs, rhs, lambda);
11600
11601 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowrhs);
11602 }
11603 else
11604 {
11605 SCIP_Real lhsslack;
11606 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
11607 assert(!SCIPisInfinity(scip, -row->lhs));
11608
11609 lhsslack = SCIPgetRowMaxActivity(scip, row) - rowlhs;
11610 slackub = aggrrow->rowweights[i] * MIN(lhsslack, slackub);
11611
11612 if( SCIPisGE(scip, slackub, lambda) )
11613 SCIPquadprecSumQD(rhs, rhs, lambda);
11614
11615 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowlhs);
11616 }
11617 }
11618 }
11619
11620 *cutrhs = QUAD_TO_DBL(rhs);
11621
11622 /* relax rhs to zero, if it's very close to 0 */
11623 if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
11624 *cutrhs = 0.0;
11625
11626 return SCIP_OKAY;
11627}
11628
11629/** calculates a lifted simple generalized flow cover cut out of the weighted sum of LP rows given by an aggregation row; the
11630 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
11631 * participate in the cut.
11632 * For further details we refer to:
11633 *
11634 * Gu, Z., Nemhauser, G. L., & Savelsbergh, M. W. (1999). Lifted flow cover inequalities for mixed 0-1 integer programs.
11635 * Mathematical Programming, 85(3), 439-467.
11636 *
11637 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
11638 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
11639 *
11640 * @pre This method can be called if @p scip is in one of the following stages:
11641 * - \ref SCIP_STAGE_SOLVING
11642 *
11643 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
11644 */
11646 SCIP* scip, /**< SCIP data structure */
11647 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
11648 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
11649 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
11650 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
11651 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
11652 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
11653 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
11654 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
11655 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
11656 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
11657 int* cutrank, /**< pointer to return rank of generated cut */
11658 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
11659 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
11660 )
11661{
11662 int i;
11663 int nvars;
11664 SCIP_Bool localbdsused;
11665 SNF_RELAXATION snf;
11666 SCIP_Real lambda;
11667 SCIP_Real* tmpcoefs;
11668 int *transvarflowcoverstatus;
11669 int nflowcovervars;
11670 int nnonflowcovervars;
11671
11672 nvars = SCIPgetNVars(scip);
11673
11674 *success = FALSE;
11675
11676 /* get data structures */
11677 SCIP_CALL( SCIPallocBufferArray(scip, &transvarflowcoverstatus, nvars) );
11678 SCIP_CALL( allocSNFRelaxation(scip, &snf, nvars) );
11679
11680 SCIPdebug( printCutQuad(scip, sol, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, FALSE, aggrrow->local) );
11681
11682 SCIP_CALL( constructSNFRelaxation(scip, sol, boundswitch, allowlocal, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, &snf, success, &localbdsused) );
11683
11684 if( ! *success )
11685 {
11686 goto TERMINATE;
11687 }
11688
11689 *cutislocal = aggrrow->local || localbdsused;
11690
11691 /* initialize lambda because gcc issues a stupid warning */
11692 lambda = 0.0;
11693 SCIP_CALL( getFlowCover(scip, &snf, &nflowcovervars, &nnonflowcovervars, transvarflowcoverstatus, &lambda, success) );
11694
11695 if( ! *success )
11696 {
11697 goto TERMINATE;
11698 }
11699
11700 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
11701
11702 SCIP_CALL( generateLiftedFlowCoverCut(scip, &snf, aggrrow, transvarflowcoverstatus, lambda, tmpcoefs, cutrhs, cutinds, cutnnz, success) );
11703 SCIPdebugMsg(scip, "computed flowcover_%lli_%i:\n", SCIPgetNLPs(scip), SCIPgetNCuts(scip));
11704
11705 /* if success is FALSE generateLiftedFlowCoverCut wont have touched the tmpcoefs array so we dont need to clean it then */
11706 if( *success )
11707 {
11708 if( postprocess )
11709 {
11710 SCIP_CALL( postprocessCut(scip, *cutislocal, cutinds, tmpcoefs, cutnnz, cutrhs, success) );
11711 }
11712 else
11713 {
11714 SCIP_Real QUAD(rhs);
11715
11716 QUAD_ASSIGN(rhs, *cutrhs);
11717 *success = ! removeZeros(scip, SCIPsumepsilon(scip), *cutislocal, tmpcoefs, QUAD(&rhs), cutinds, cutnnz);
11718 *cutrhs = QUAD_TO_DBL(rhs);
11719 }
11720
11721 if( *success )
11722 {
11723 /* store cut sparse and calculate efficacy */
11724 for( i = 0; i < *cutnnz; ++i )
11725 {
11726 int j = cutinds[i];
11727 assert(tmpcoefs[j] != 0.0);
11728 cutcoefs[i] = tmpcoefs[j];
11729 tmpcoefs[j] = 0.0;
11730 }
11731
11732 if( cutefficacy != NULL )
11733 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
11734
11735 if( cutrank != NULL )
11736 *cutrank = aggrrow->rank + 1;
11737 }
11738 else
11739 {
11740 /* clean buffer array */
11741 for( i = 0; i < *cutnnz; ++i )
11742 {
11743 int j = cutinds[i];
11744 assert(tmpcoefs[j] != 0.0);
11745 tmpcoefs[j] = 0.0;
11746 }
11747 }
11748 }
11749
11750 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
11751
11752 TERMINATE:
11754 SCIPfreeBufferArray(scip, &transvarflowcoverstatus);
11755
11756 return SCIP_OKAY;
11757}
11758
11759/* =========================================== knapsack cover =========================================== */
11760
11761/** Relax the row to a possibly fractional knapsack row containing no integer or continuous variables
11762 * and only having positive coefficients for binary variables. General integer and continuous variables
11763 * are complemented with variable or simple bounds such that their coefficient becomes positive and then
11764 * it is relaxed to zero.
11765 * All remaining binary variables are complemented with simple upper or lower bounds such that their
11766 * coefficient becomes positive.
11767 */
11768static
11770 SCIP* scip, /**< SCIP data structure */
11771 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
11772 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
11773 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
11774 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
11775 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
11776 int* nnz, /**< number of non-zeros in cut */
11777 int* varsign, /**< stores the sign of the transformed variable in summation */
11778 int* boundtype, /**< stores the bound used for transformed variable:
11779 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
11780 SCIP_Bool* localbdsused, /**< pointer to store whether local bounds were used in transformation */
11781 SCIP_Bool* success /**< stores whether the row could successfully be transformed into a knapsack constraint.
11782 * Returns FALSE in case a continuous or general integer variable is unbounded in the
11783 * required direction. */
11784 )
11785{
11786 SCIP_Real* bestbds;
11787 int i;
11788 int aggrrowbinstart;
11789 int firstnonbinvar;
11790 SCIP_VAR** vars;
11791
11792 assert(varsign != NULL);
11793 assert(boundtype != NULL);
11794 assert(success != NULL);
11795 assert(localbdsused != NULL);
11796
11797 *success = FALSE;
11798
11799 /* allocate temporary memory to store best bounds and bound types */
11800 SCIP_CALL( SCIPallocBufferArray(scip, &bestbds, 2*(*nnz)) );
11801
11802 /* start with continuous variables, because using variable bounds can affect the untransformed binary
11803 * variables, and these changes have to be incorporated in the transformation of the binary variables
11804 * (binary variables have the smallest problem indices!)
11805 */
11806 SCIPsortDownInt(cutinds, *nnz);
11807
11808 vars = SCIPgetVars(scip);
11809 firstnonbinvar = SCIPgetNBinVars(scip);
11810
11811 /* determine best bounds for the continuous and general integer variables such that they will have
11812 * a positive coefficient in the transformation */
11813 for( i = 0; i < *nnz && cutinds[i] >= firstnonbinvar; ++i )
11814 {
11815 SCIP_Real QUAD(coef);
11816 int v = cutinds[i];
11817
11818 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
11819
11820 if( QUAD_TO_DBL(coef) > 0.0 )
11821 {
11822 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable
11823 * so that it will have a positive coefficient */
11824 SCIP_CALL( findBestLb(scip, vars[v], sol, SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ? 1 : 0, allowlocal, bestbds + i, boundtype + i) );
11825
11826 /* cannot transform into knapsack */
11827 if( SCIPisInfinity(scip, -bestbds[i]) )
11828 goto TERMINATE;
11829
11830 varsign[i] = +1;
11831 }
11832 else if( QUAD_TO_DBL(coef) < 0.0 )
11833 {
11834 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable
11835 * so that it will have a positive coefficient */
11836 SCIP_CALL( findBestUb(scip, vars[v], sol, SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ? 1 : 0, allowlocal, bestbds + i, boundtype + i) );
11837
11838 /* cannot transform into knapsack */
11839 if( SCIPisInfinity(scip, bestbds[i]) )
11840 goto TERMINATE;
11841
11842 varsign[i] = -1;
11843 }
11844 }
11845
11846 /* remember start of integer variables in the aggrrow */
11847 aggrrowbinstart = i;
11848
11849 /* perform bound substitution for continuous variables */
11850 for( i = 0; i < aggrrowbinstart; ++i )
11851 {
11852 SCIP_Real QUAD(coef);
11853 int v = cutinds[i];
11854
11855 performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestbds[i], v, localbdsused);
11856
11857 /* relax non-binary coefficient to zero after bound substitution */
11858 QUAD_ASSIGN(coef, 0.0);
11859 QUAD_ARRAY_STORE(cutcoefs, v, coef);
11860 }
11861
11862 assert(i == aggrrowbinstart);
11863
11864 /* remove non-binary variables because their coefficients have been set to zero after bound substitution */
11865 if( aggrrowbinstart != 0 )
11866 {
11867 *nnz -= aggrrowbinstart;
11868 BMSmoveMemoryArray(cutinds, cutinds + aggrrowbinstart, *nnz);
11869 }
11870 i = 0;
11871
11872 /* after doing bound substitution of non-binary vars, some coefficients of binary vars might have changed, so here we
11873 * remove the ones that became 0 if any; also, we need that all remaining binary vars have positive coefficients,
11874 * thus we perform bound substitution with simple bounds (i.e. complementing) to achieve this.
11875 */
11876 while( i < *nnz )
11877 {
11878 SCIP_Real QUAD(coef);
11879 SCIP_Real bestlb;
11880 SCIP_Real bestub;
11881 SCIP_Bool setzero;
11882 int v = cutinds[i];
11883
11884 assert(SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY && !SCIPvarIsImpliedIntegral(vars[v]));
11885
11886 assert(v < firstnonbinvar);
11887 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
11888
11889 /* due to variable bound usage for bound substitution of continuous variables cancellation may have occurred */
11890 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
11891 {
11892 /* do not increase i, since last element is copied to the i-th position */
11893 setzero = TRUE;
11894 }
11895 else
11896 {
11897 /* perform bound substitution */
11898 if( QUAD_TO_DBL(coef) < 0.0 )
11899 {
11900 SCIP_CALL( findBestUb(scip, vars[v], sol, 0, allowlocal, &bestub, boundtype + i) );
11901
11902 if( SCIPisZero(scip, bestub) )
11903 {
11904 /* binary variable is fixed to zero */
11905 setzero = TRUE;
11906 *localbdsused = *localbdsused || (boundtype[i] == -2);
11907 }
11908 else
11909 {
11910 varsign[i] = -1;
11911
11912 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestub, v, localbdsused);
11913 QUAD_ARRAY_STORE(cutcoefs, v, -coef);
11914 setzero = FALSE;
11915 }
11916 }
11917 else
11918 {
11919 SCIP_CALL( findBestLb(scip, vars[v], sol, 0, allowlocal, &bestlb, boundtype + i) );
11920
11921 if( !SCIPisZero(scip, bestlb) )
11922 {
11923 /* binary variable is fixed to one */
11924 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlb, v, localbdsused);
11925 setzero = TRUE;
11926 }
11927 else
11928 {
11929 varsign[i] = +1;
11930 setzero = FALSE;
11931 }
11932 }
11933
11934 assert(boundtype[i] == -1 || boundtype[i] == -2);
11935 }
11936
11937 /* increase i or remove zero coefficient (i.e. var with 0 coef) by shifting last nonzero to current position */
11938 if( setzero )
11939 {
11940 QUAD_ASSIGN(coef, 0.0);
11941 QUAD_ARRAY_STORE(cutcoefs, v, coef);
11942 --(*nnz);
11943 cutinds[i] = cutinds[*nnz];
11944 }
11945 else
11946 ++i;
11947 }
11948
11949 /* relax rhs to zero if it is close to but slightly below zero */
11950 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
11951 QUAD_ASSIGN(*cutrhs, 0.0);
11952
11953 *success = TRUE;
11954 TERMINATE:
11955 /*free temporary memory */
11956 SCIPfreeBufferArray(scip, &bestbds);
11957
11958 return SCIP_OKAY;
11959}
11960
11961/** determines the initial cover for the given (fractional) knapsack row */
11962static
11964 SCIP* scip, /**< SCIP datastructure */
11965 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
11966 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
11967 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
11968 SCIP_Real cutrhs, /**< pointer to the right hand side of the cut */
11969 int cutnnz, /**< pointer to the number of non-zeros in the cut */
11970 int* varsign, /**< sign of coefficients for each nonzero in the row be transformation */
11971 int* coverstatus, /**< array to return the coverstatus for each variable in the knapsack row */
11972 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
11973 SCIP_Real* covervals, /**< coefficient value of each variable in the cover */
11974 int* coversize, /**< pointer to return number of variables in the cover;
11975 * matches the length of the associated arrays */
11976 QUAD(SCIP_Real* coverweight) /**< pointer to return the weight of the cover;
11977 * the weight is the sum of the coefficient values of variables in the cover */
11978 )
11979{
11980 SCIP_VAR** vars;
11981 int k;
11982 int j;
11983 QUAD_ASSIGN(*coverweight, 0);
11984 *coversize = 0;
11985 j = cutnnz-1;
11986 vars = SCIPgetVars(scip);
11987
11988 for( k = 0; k < cutnnz; ++k )
11989 {
11990 SCIP_Real solval;
11991 int v = cutinds[k];
11992 SCIP_Real QUAD(coef);
11993 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
11994
11995 solval = SCIPgetSolVal(scip, sol, vars[v]);
11996 if( varsign[k] == -1 )
11997 solval = 1 - solval;
11998
11999 if( SCIPisFeasEQ(scip, solval, 1.0) )
12000 {
12001 /* every variable with solution value 1 is forced into the cover */
12002 coverpos[*coversize] = k;
12003 covervals[*coversize] = QUAD_TO_DBL(coef);
12004 coverstatus[k] = 1;
12005 *coversize += 1;
12006 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
12007 }
12008 else
12009 {
12010 coverpos[j] = k;
12011 covervals[j] = solval * QUAD_TO_DBL(coef);
12012 coverstatus[k] = 0;
12013 j -= 1;
12014 }
12015 }
12016
12017 /* Use these two arrays to sort the variables by decreasing contribution
12018 * and pick them greedily in the while loop below until they are a cover.
12019 * Since the cover does not need to be minimal we do not need to remove any of the
12020 * variables with a high activity contribution even if they are not necessary after
12021 * picking the last variable.
12022 */
12023 SCIPsortDownRealInt(covervals + (*coversize), coverpos + (*coversize), cutnnz - (*coversize));
12024
12025 /* overwrite covervals with the coefficients of the variables in the cover
12026 * as we need to sort decreasingly by those again for the lifting
12027 */
12028 while( *coversize < cutnnz &&
12029 SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) )
12030 {
12031 int v;
12032 SCIP_Real QUAD(coef);
12033 k = coverpos[*coversize];
12034 v = cutinds[k];
12035 coverstatus[k] = 1;
12036 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
12037 covervals[*coversize] = QUAD_TO_DBL(coef);
12038 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
12039 *coversize += 1;
12040 }
12041
12042 /* there is no cover */
12043 if( SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) || *coversize == 0 )
12044 return FALSE;
12045
12046 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(*coverweight), cutrhs);
12047 assert(*coversize > 0);
12048
12049 return TRUE;
12050}
12051
12052/** prepares the data needed to evaluate the lifting function */
12053static
12055 SCIP* scip, /**< SCIP datastructure */
12056 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
12057 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
12058 QUAD(SCIP_Real cutrhs), /**< pointer to the right hand side of the cut */
12059 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
12060 int coversize, /**< number of variables in the cover */
12061 QUAD(SCIP_Real coverweight), /**< weight of cover */
12062 SCIP_Real* covervals, /**< coefficient value of each variable in the cover;
12063 * on output stores the running sum of S^-(*) values */
12064 int* coverstatus, /**< coverstatus for each variable in the cover. After calling this function
12065 * variables in C^- will have the value -1, variables in C^+ the value 1,
12066 * and all variables outside the cover keep the value 0. */
12067 QUAD(SCIP_Real* abar), /**< pointer to store the reciprocal value of \bar{a} */
12068 int* cplussize /**< pointer to store the size of C^+ */
12069 )
12070{
12071 int k;
12072 SCIP_Real QUAD(tmp);
12073 SCIP_Real QUAD(sigma);
12074
12075 /* Now compute \bar{a}, the unique rational number such that for the cover C it holds that
12076 * b = \sum_{a_i \in C} \min(\bar{a}, a_i).
12077 * For that we need to sort by decreasing coefficients of the variables in the cover.
12078 * After the sorting the covervals array is free to be reused.
12079 */
12080 SCIPsortDownRealInt(covervals, coverpos, coversize);
12081
12082 /* Now follows Algorithm 1 in the paper to compute \bar{a} */
12083
12084 /* set \bar{a} = l_1 */
12085 QUAD_ARRAY_LOAD(*abar, cutcoefs, cutinds[coverpos[0]]);
12086 SCIPquadprecSumQQ(sigma, coverweight, -cutrhs);
12087
12088 for( k = 1; k < coversize; ++k )
12089 {
12090 SCIP_Real QUAD(lkplus1);
12091 SCIP_Real QUAD(kdelta);
12092
12093 /* load next coefficient l_{k+1} in sorted order of cover */
12094 QUAD_ARRAY_LOAD(lkplus1, cutcoefs, cutinds[coverpos[k]]);
12095
12096 /* Let \delta = \bar{a} - l_{k+1} and compute k * \delta */
12097 SCIPquadprecSumQQ(kdelta, *abar, -lkplus1);
12098 SCIPquadprecProdQD(kdelta, kdelta, k);
12099
12100 /* Set tmp = k * \delta - \sigma to check condition k * \delta < \sigma by tmp < 0 */
12101 SCIPquadprecSumQQ(tmp, kdelta, -sigma);
12102 if( QUAD_TO_DBL(tmp) < 0.0 )
12103 {
12104 /* Set \bar{a} = l_{k+1} and \sigma = \sigma - k*\delta */
12105 QUAD_ASSIGN_Q(*abar, lkplus1);
12106 SCIPquadprecSumQQ(sigma, sigma, -kdelta);
12107 }
12108 else
12109 {
12110 /* Set \bar{a} = \bar{a} - \sigma / k and \sigma = 0; break; */
12111 SCIP_Real minusoneoverk = -1.0 / k;
12112 SCIPquadprecProdQD(sigma, sigma, minusoneoverk);
12113 SCIPquadprecSumQQ(*abar, *abar, sigma);
12114 QUAD_ASSIGN(sigma, 0.0);
12115 break;
12116 }
12117 }
12118
12119 if( QUAD_TO_DBL(sigma) > 0.0 )
12120 {
12121 SCIP_Real oneoverc = 1.0 / coversize;
12122 SCIPquadprecProdQD(*abar, cutrhs, oneoverc);
12123 }
12124
12125 /* now we partition C into C^+ and C^-, where C^+ are all the elements of C whose weight is strictly larger than
12126 * \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
12127 * compute S^-(h) = sum of the h largest a_i^- and store S^-(h+1) in in covervals[h], for k = 0, ..., coversize - 1
12128 * (S^-(0) = 0 so it doesn't need to be stored; we use S to compute the lifted cut, see below)
12129 * we remember which elements of C^- in coverstatus, so that element in C^+ have coverstatus 1 and
12130 * elements in C^- have coverstatus -1 (elements not in C have coverstatus 0)
12131 */
12132 QUAD_ASSIGN(tmp, 0.0);
12133 *cplussize = 0;
12134 for( k = 0; k < coversize; ++k )
12135 {
12136 SCIP_Real QUAD(coef);
12137 SCIP_Real QUAD(coefminusabar);
12138
12139 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[coverpos[k]]);
12140 SCIPquadprecSumQQ(coefminusabar, coef, -*abar);
12141 if( QUAD_TO_DBL(coefminusabar) > 0.0 )
12142 {
12143 /* coefficient is in C^+ because it is greater than \bar{a} and contributes only \bar{a} to the sum */
12144 SCIPquadprecSumQQ(tmp, tmp, *abar);
12145
12146 /* rather be on the safe side in numerical corner cases and relax the coefficient to exactly \bar{a}.
12147 * In that case the coefficient is not treated as in C^+ but as being <= \bar{a} and therefore in C^-.
12148 */
12149 if( QUAD_TO_DBL(coefminusabar) > SCIPfeastol(scip) )
12150 ++(*cplussize);
12151 else
12152 coverstatus[coverpos[k]] = -1;
12153 }
12154 else
12155 {
12156 /* coefficient is in C^- because it is smaller or equal to \bar{a} */
12157 coverstatus[coverpos[k]] = -1;
12158 SCIPquadprecSumQQ(tmp, tmp, coef);
12159 }
12160 covervals[k] = QUAD_TO_DBL(tmp);
12161 SCIPdebugMsg(scip, "S^-(%d) = %g\n", k + 1, covervals[k]);
12162 }
12163
12164 /* set abar to its reciprocal for faster computation of the lifting coefficients */
12165 SCIPquadprecDivDQ(*abar, 1, *abar);
12166}
12167
12168/** evaluate the lifting function based on the given values */
12169static
12171 SCIP* scip, /**< SCIP datastructure */
12172 QUAD(SCIP_Real x), /**< value to evaluate the lifting function at */
12173 QUAD(SCIP_Real abar), /**< the reciprocal value of \bar{a} */
12174 SCIP_Real* covervals, /**< the running sum of S^-(*) values */
12175 int coversize, /**< the size of the cover */
12176 int cplussize, /**< the size of C^+ */
12177 SCIP_Real* scale /**< pointer to update the scale to integrality when a fractional value is returned */
12178 )
12179{
12180 SCIP_Real QUAD(tmp);
12181 SCIP_Real QUAD(hfrac);
12182 SCIP_Real cutcoef;
12183 SCIP_Real hreal;
12184 int h;
12185
12186 /* the lifted value is at least the coeficient (a_k) divided by \bar{a} because the largest value
12187 * contributed to the running sum stored in C is \bar{a}
12188 * therefore we start the search for the correct h at floor(a_k / \bar{a})
12189 */
12190
12191 SCIPdebugMsg(scip, "coef is %g, coversize is %d\n", QUAD_TO_DBL(x), coversize );
12192
12193 SCIPquadprecProdQQ(hfrac, x, abar);
12194
12195 /* if the coefficient is below \bar{a}, i.e. a / \bar{a} < 1 then g(a_k) = 0, otherwise g(a_k) > 0 */
12196 if( QUAD_TO_DBL(hfrac) < 1 )
12197 return 0.0;
12198
12199 /* we perform h = MIN(h, coversize) in floating-point first because on some instances h was seen to exceed the range
12200 * of int */
12201 hreal = SCIPfloor(scip, QUAD_TO_DBL(hfrac));
12202 if( hreal > (SCIP_Real)coversize )
12203 h = coversize;
12204 else
12205 h = (int)hreal;
12206
12207 SCIPquadprecSumQD(hfrac, hfrac, -h);
12208
12209 assert(h > 0);
12210 if( h < cplussize && ABS(QUAD_TO_DBL(hfrac)) <= QUAD_EPSILON )
12211 {
12212 /* cutcoef can be increased by 0.5 because it is a multiple of \bar{a}
12213 * (This is the first non-dominated lifting function presented in the paper)
12214 */
12215 cutcoef = 0.5;
12216 *scale = 2.0;
12217 }
12218 else
12219 cutcoef = 0.0;
12220
12221 /* decrease by one to make sure rounding errors or coefficients that are larger than the right hand side by themselves
12222 * did not push h too far */
12223 h--;
12224
12225 /* now increase coefficient to its lifted value based on its size relative to the S^- values.
12226 * The coefficient a_i is lifted to the unique integer h such that S^-(h) < a_i <= S^-(h+1).
12227 * (todo: variables that have a coefficient above the right hand side can get an arbitrarily large coefficient but can
12228 * also be trivially fixed using the base row. Currently they get the coefficient |C| which is 1 above the right hand
12229 * side in the cover cut so that they can still be trivially fixed by propagating the cover cut.
12230 * We do not want to apply fixings here though because the LP should stay flushed during separation.
12231 * Possibly add a parameter to return additional fixings to the caller of the SCIPcalc*() functions in here
12232 * and the caller can add them as cuts to the sepastore or we add them to the sepastore here?)
12233 */
12234 while( h < coversize )
12235 {
12236 SCIPquadprecSumQD(tmp, x, -covervals[h]); /* recall: covervals[h] = S^-(h+1) */
12237 /* compare with standard epsilon tolerance since computation involves abar, which is computed like an activity */
12238 if( !SCIPisPositive(scip, QUAD_TO_DBL(tmp)) )
12239 break;
12240
12241 ++h;
12242 }
12243
12244 cutcoef += h;
12245
12246 SCIPdebugMsg(scip, "x is %g, coversize is %d, h is %d\n", QUAD_TO_DBL(x), coversize, h );
12247 /* the lifted coefficient is h increased possibly by 0.5 for the case checked above */
12248 SCIPdebugMsg(scip, "lifted coef %g < %g <= %g to %g\n", h == 0 ? 0 : covervals[h-1], QUAD_TO_DBL(x),
12249 covervals[h], cutcoef);
12250
12251 return cutcoef;
12252}
12253
12254/** calculates a lifted knapsack cover cut out of the weighted sum of LP rows given by an aggregation row; the
12255 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
12256 * participate in the cut.
12257 * For further details we refer to:
12258 *
12259 * Letchford, A. N., & Souli, G. (2019). On lifted cover inequalities: A new lifting procedure with unusual properties.
12260 * Operations Research Letters, 47(2), 83-87.
12261 *
12262 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
12263 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
12264 *
12265 * @pre This method can be called if @p scip is in one of the following stages:
12266 * - \ref SCIP_STAGE_SOLVING
12267 *
12268 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
12269 */
12271 SCIP* scip, /**< SCIP data structure */
12272 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
12273 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
12274 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
12275 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
12276 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
12277 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
12278 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
12279 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
12280 int* cutrank, /**< pointer to return rank of generated cut */
12281 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
12282 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
12283 )
12284{
12285 int* varsign;
12286 int* boundtype;
12287 int* coverstatus;
12288 int* coverpos;
12289 int* tmpinds;
12290 SCIP_Real* tmpcoefs;
12291 SCIP_Real* covervals;
12292 SCIP_Real QUAD(rhs);
12293 SCIP_Real QUAD(coverweight);
12294 SCIP_Real QUAD(abar);
12295 SCIP_Bool transformed;
12296 SCIP_Bool local;
12297 SCIP_Real efficacy;
12298 SCIP_Real scale;
12299 int k;
12300 int nvars;
12301 int coversize;
12302 int cplussize;
12303 int nnz;
12304
12305 assert(scip != NULL);
12306 assert(aggrrow != NULL);
12307 assert(cutcoefs != NULL);
12308 assert(cutrhs != NULL);
12309 assert(cutinds != NULL);
12310 assert(cutnnz != NULL);
12311 assert(cutefficacy != NULL);
12312 assert(cutislocal != NULL);
12313 assert(success != NULL);
12314
12315 *success = FALSE;
12316
12317 if( aggrrow->nnz == 0 )
12318 return SCIP_OKAY;
12319
12320 for( k = 0; k < aggrrow->nrows; ++k )
12321 {
12322 /* cannot handle negative slack variables */
12323 if( aggrrow->rowweights[k] * aggrrow->slacksign[k] < 0 )
12324 return SCIP_OKAY;
12325 }
12326
12327 /* allocate temporary memory */
12328 nvars = SCIPgetNVars(scip);
12329 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
12330 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
12331 SCIP_CALL( SCIPallocBufferArray(scip, &coverstatus, nvars) );
12332 SCIP_CALL( SCIPallocBufferArray(scip, &covervals, nvars) );
12333 SCIP_CALL( SCIPallocBufferArray(scip, &coverpos, nvars) );
12334 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
12336
12337 /* initialize cut with aggregation */
12338 nnz = aggrrow->nnz;
12339 QUAD_ASSIGN_Q(rhs, aggrrow->rhs);
12340
12341 BMScopyMemoryArray(tmpinds, aggrrow->inds, nnz);
12342
12343 for( k = 0; k < nnz; ++k )
12344 {
12345 SCIP_Real QUAD(coef);
12346 int j = tmpinds[k];
12347
12348 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
12349
12350 QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
12351 assert(QUAD_HI(coef) != 0.0);
12352
12353 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
12354 }
12355 SCIPdebugMsg(scip, "Computing lifted knapsack cover for ");
12356 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
12357
12358 /* Transform aggregated row into a (fractional, i.e. with possibly fractional weights) knapsack constraint.
12359 * Uses simple or variable lower or upper bounds to relax out continuous and general integers
12360 * so that only binary variables remain and complements those such that they have a positive coefficient.
12361 */
12362 local = aggrrow->local;
12363 SCIP_CALL( cutsTransformKnapsackCover(scip, sol, allowlocal,
12364 tmpcoefs, QUAD(&rhs), tmpinds, &nnz, varsign, boundtype, &local, &transformed) );
12365
12366 assert(allowlocal || !local);
12367
12368 if( !transformed )
12369 goto TERMINATE;
12370
12371 SCIPdebugMsg(scip, "Transformed knapsack relaxation ");
12372 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
12373
12374 if( !computeInitialKnapsackCover(scip, sol, tmpcoefs, tmpinds, QUAD_TO_DBL(rhs), nnz, varsign, coverstatus,
12375 coverpos, covervals, &coversize, QUAD(&coverweight)) )
12376 goto TERMINATE;
12377
12378 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(coverweight), QUAD_TO_DBL(rhs));
12379 assert(coversize > 0);
12380
12381 /* by default do not scale the cut */
12382 scale = 1.0;
12383
12384 if( coversize == 1 )
12385 {
12386 SCIP_Real QUAD(tmp);
12387 /* cover is trivial, return the fixing as cut */
12388 QUAD_ASSIGN(tmp, 0.0);
12389 for( k = 0; k < nnz; ++k )
12390 {
12391 if( coverstatus[k] == 0 )
12392 {
12393 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
12394 }
12395 else
12396 {
12397 tmpinds[0] = tmpinds[k];
12398 varsign[0] = varsign[k];
12399 }
12400 }
12401
12402 nnz = 1;
12403 if( varsign[0] == -1 )
12404 {
12405 QUAD_ASSIGN(rhs, -1.0);
12406 QUAD_ASSIGN(tmp, -1.0);
12407 }
12408 else
12409 {
12410 QUAD_ASSIGN(rhs, 0.0);
12411 QUAD_ASSIGN(tmp, 1.0);
12412 }
12413
12414 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[0], tmp);
12415 }
12416 else
12417 {
12418 SCIP_Real QUAD(tmp);
12419
12420 /* compute lifted cover inequality:
12421 * sum_{i \in C^-) x_i + sum_{i \in N \ C^-) g(a_i) x_i <= c - 1
12422 * where g(z) is equal to
12423 * - 0 if z is 0 (irrelevant as there shouldn't be element with weight 0 in the knapsack)
12424 * - 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
12425 * - h if S^-(h) < z <= S^-(h+1) for some h = 0, ..., coversize -1
12426 * the function S^- is defined above. Note that S^-(0) = 0
12427 * we store the cut coefficients in tmpcoef
12428 */
12429
12430 SCIPdebugMsg(scip, "call prepareLiftingData: \n");
12431 /* prepare data required to evaluate lifting function */
12432 prepareLiftingData(scip, tmpcoefs, tmpinds, QUAD(rhs), coverpos, coversize,
12433 QUAD(coverweight), covervals, coverstatus, QUAD(&abar), &cplussize);
12434
12435 /* compute lifted cover inequality */
12436 QUAD_ASSIGN(rhs, (coversize - 1));
12437 for( k = 0; k < nnz; )
12438 {
12439 SCIP_Real cutcoef;
12440 if( coverstatus[k] == -1 )
12441 { /* variables in C^- get the coefficients 1 */
12442 cutcoef = 1.0;
12443 }
12444 else
12445 { /* variables is either in C^+ or not in the cover and its coefficient value is computed with the lifing function */
12446 SCIP_Real QUAD(coef);
12447
12448 SCIPdebugMsg(scip, "load QUAD(coef) from tmpcoefs[tmpinds[k] = %d]\n",tmpinds[k]);
12449 QUAD_ARRAY_LOAD(coef, tmpcoefs, tmpinds[k]);
12450
12451 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));
12452
12453 SCIPdebugMsg(scip, "call evaluateLiftingFunctionKnapsack:\n");
12454 cutcoef = evaluateLiftingFunctionKnapsack(scip, QUAD(coef), QUAD(abar), covervals, coversize, cplussize, &scale);
12455
12456 /* if the coefficient value is zero then remove the nonzero entry and continue */
12457 if( cutcoef == 0.0 )
12458 {
12459 QUAD_ASSIGN(tmp, 0.0);
12460 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
12461 --nnz;
12462 coverstatus[k] = coverstatus[nnz];
12463 tmpinds[k] = tmpinds[nnz];
12464 varsign[k] = varsign[nnz];
12465 continue;
12466 }
12467 }
12468
12469 /* directly undo the complementation before storing back the coefficient */
12470 if( varsign[k] == -1 )
12471 {
12472 /* variable was complemented so we have cutcoef * (1-x) = cutcoef - cutcoef * x.Thus we need to adjust the rhs
12473 * to rhs - cutcoef and flip the sign of cutcoef */
12474 cutcoef = -cutcoef;
12475 SCIPquadprecSumQD(rhs, rhs, cutcoef);
12476 }
12477
12478 QUAD_ASSIGN(tmp, cutcoef);
12479 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
12480
12481 ++k;
12482 }
12483 }
12484
12485 /* calculate the efficacy of the computed cut and store the success flag if the efficacy exceeds the
12486 * one stored in the cutefficacy variable by the caller
12487 */
12488 efficacy = calcEfficacyDenseStorageQuad(scip, sol, tmpcoefs, QUAD_TO_DBL(rhs), tmpinds, nnz);
12489 *success = SCIPisGT(scip, efficacy, *cutefficacy);
12490
12491 SCIPdebugMsg(scip, "FINAL LCI:");
12492 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
12493
12494 if( *success )
12495 {
12496 /* return the cut into the given arrays/pointers */
12497 *cutislocal = local;
12498 *cutrhs = scale * QUAD_TO_DBL(rhs);
12499 *cutnnz = nnz;
12500
12501 /* store cut in given array in sparse representation and clean buffer array */
12502 for( k = 0; k < nnz; ++k )
12503 {
12504 SCIP_Real QUAD(coef);
12505 int j = tmpinds[k];
12506
12507 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
12508 assert(QUAD_HI(coef) != 0.0);
12509
12510 cutcoefs[k] = scale * QUAD_TO_DBL(coef);
12511 cutinds[k] = j;
12512 QUAD_ASSIGN(coef, 0.0);
12513 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
12514 }
12515
12516 assert( cutefficacy != NULL );
12517 /* calculate efficacy again to make sure it matches the coefficients after they where rounded to double values
12518 * and after the cleanup and postprocessing step was applied. */
12519 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, nnz);
12520
12521 if( cutrank != NULL )
12522 *cutrank = aggrrow->rank + 1;
12523 }
12524
12525 TERMINATE:
12526
12527 /* if we aborted early the tmpcoefs array needs to be cleaned */
12528 if( !(*success) )
12529 {
12530 SCIP_Real QUAD(tmp);
12531 QUAD_ASSIGN(tmp, 0.0);
12532
12533 for( k = 0; k < nnz; ++k )
12534 {
12535 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
12536 }
12537 }
12538#ifndef NDEBUG
12539 for( k = 0; k < QUAD_ARRAY_SIZE(nvars); ++k )
12540 {
12541 if(tmpcoefs[k] != 0.0)
12542 {
12543 SCIPdebugMsg(scip, "tmpcoefs have not been reset\n");
12544 SCIPABORT();
12545 }
12546 }
12547#endif
12548
12549 /* free temporary memory */
12550 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
12551 SCIPfreeBufferArray(scip, &tmpinds);
12552 SCIPfreeBufferArray(scip, &coverpos);
12553 SCIPfreeBufferArray(scip, &covervals);
12554 SCIPfreeBufferArray(scip, &coverstatus);
12555 SCIPfreeBufferArray(scip, &boundtype);
12556 SCIPfreeBufferArray(scip, &varsign);
12557
12558 return SCIP_OKAY;
12559}
12560
12561
12562/* =========================================== strongcg =========================================== */
12563
12564/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
12565 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
12566 *
12567 * Differs from cutsTransformMIR for continuous variables for which the lower bound must be used
12568 * when in case their coefficient is positive and the upper bound in case their coefficient is
12569 * negative. This forces all continuous variable to have a positive coefficient in the transformed
12570 * row.
12571 *
12572 * Transform variables (lb or ub):
12573 * \f[
12574 * \begin{array}{llll}
12575 * 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}\\
12576 * 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}
12577 * \end{array}
12578 * \f]
12579 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
12580 *
12581 * Transform variables (vlb or vub):
12582 * \f[
12583 * \begin{array}{llll}
12584 * 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.} \\
12585 * 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.}
12586 * \end{array}
12587 * \f]
12588 * 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:
12589 * \f[
12590 * \begin{array}{ll}
12591 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
12592 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
12593 * \end{array}
12594 * \f]
12595 */
12596static
12598 SCIP* scip, /**< SCIP datastructure */
12599 MIR_DATA* data, /**< the MIR data structure for this cut */
12600 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
12601 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
12602 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
12603 int* varsign, /**< stores the sign of the transformed variable in summation */
12604 int* boundtype, /**< stores the bound used for transformed variable:
12605 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
12606 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
12607 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
12608 )
12609{
12610 SCIP_Real* bestlbs;
12611 SCIP_Real* bestubs;
12612 int* bestlbtypes;
12613 int* bestubtypes;
12614 SCIP_BOUNDTYPE* selectedbounds;
12615 int totalnnz;
12616 int s;
12617 int i;
12618
12619 assert(data != NULL);
12620 assert(varsign != NULL);
12621 assert(boundtype != NULL);
12622 assert(freevariable != NULL);
12623 assert(localbdsused != NULL);
12624
12625 totalnnz = data->totalnnz;
12626
12627 *freevariable = FALSE;
12628 *localbdsused = FALSE;
12629
12630 /* allocate temporary memory to store best bounds and bound types */
12631 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*totalnnz) );
12632 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*totalnnz) );
12633 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*totalnnz) );
12634 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*totalnnz) );
12635 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*totalnnz) );
12636
12637 /* transform the cut, one variable section at a time */
12638 for( s = 0; s < NSECTIONS; ++s )
12639 {
12640 int* indices = data->secindices[s];
12641 int cutindsstart = data->ncutinds;
12642 int usevbds = data->usevbds[s];
12643
12644 i = 0;
12645 /* Iterate over all nonzeros in the section */
12646 while( i < data->secnnz[s] )
12647 {
12648 SCIP_Real QUAD(coef);
12649 int v = indices[i];
12650
12651 /* due to variable bound usage, cancellation may have occurred */
12652 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
12653 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
12654 {
12655 QUAD_ASSIGN(coef, 0.0);
12656 QUAD_ARRAY_STORE(data->cutcoefs, v, coef);
12657 --data->secnnz[s];
12658 --data->totalnnz;
12659 indices[i] = indices[data->secnnz[s]];
12660 /* do not increase the index */
12661 continue;
12662 }
12663
12664 int cutindex = data->ncutinds;
12665 /* For continuous variables, we must choose the bound substitution so that they become positive in the cut */
12666 if( !data->isenfint[s] && !data->isimplint[s] )
12667 {
12668 if( QUAD_TO_DBL(coef) > 0.0 )
12669 {
12670 SCIP_Real simplelb;
12671
12672 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
12673 SCIP_CALL( findMIRBestLb(scip, data->vars[v], sol, data, usevbds, allowlocal,
12674 bestlbs + cutindex, &simplelb, bestlbtypes + cutindex) );
12675
12676 /* cannot create transformation for strongcg cut */
12677 if( SCIPisInfinity(scip, -bestlbs[cutindex]) )
12678 {
12679 *freevariable = TRUE;
12680 goto TERMINATE;
12681 }
12682
12683 varsign[cutindex] = +1;
12684 selectedbounds[cutindex] = SCIP_BOUNDTYPE_LOWER;
12685 }
12686 else
12687 {
12688 SCIP_Real simpleub;
12689
12690 assert(QUAD_TO_DBL(coef) < 0.0);
12691
12692 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
12693 SCIP_CALL( findMIRBestUb(scip, data->vars[v], sol, data, usevbds, allowlocal,
12694 bestubs + cutindex, &simpleub, bestubtypes + cutindex) );
12695
12696 /* cannot create transformation for strongcg cut */
12697 if( SCIPisInfinity(scip, bestubs[cutindex]) )
12698 {
12699 *freevariable = TRUE;
12700 goto TERMINATE;
12701 }
12702
12703 varsign[cutindex] = -1;
12704 selectedbounds[cutindex] = SCIP_BOUNDTYPE_UPPER;
12705 }
12706 }
12707 else if( data->isimplint[s] )
12708 {
12709 /* For implied integers, we still prefer to choose the bound substitution that makes them positive, but
12710 * if we cannot manage to do so it is not an error, because we can still treat them as integer variables */
12711 SCIP_Real simplelb;
12712 SCIP_Real simpleub;
12713 SCIP_Bool lowerinf;
12714 SCIP_Bool upperinf;
12715 SCIP_Bool positive;
12716
12717 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
12718 SCIP_CALL( findMIRBestLb(scip, data->vars[v], sol, data, usevbds, allowlocal,
12719 bestlbs + cutindex, &simplelb, bestlbtypes + cutindex) );
12720
12721 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
12722 SCIP_CALL( findMIRBestUb(scip, data->vars[v], sol, data, usevbds, allowlocal,
12723 bestubs + cutindex, &simpleub, bestubtypes + cutindex) );
12724
12725 lowerinf = SCIPisInfinity(scip, -bestlbs[cutindex]);
12726 upperinf = SCIPisInfinity(scip, bestubs[cutindex]);
12727 positive = QUAD_TO_DBL(coef) > 0.0;
12728
12729 if( lowerinf && upperinf )
12730 {
12731 /* we found a free variable in the row with non-zero coefficient
12732 * -> MIR row can't be transformed in standard form
12733 */
12734 *freevariable = TRUE;
12735 goto TERMINATE;
12736 }
12737
12738 /* preferably, choose bound that makes value positive */
12739 if( (positive && lowerinf) || (!positive && !upperinf) )
12740 {
12741 varsign[cutindex] = -1;
12742 selectedbounds[cutindex] = SCIP_BOUNDTYPE_UPPER;
12743 }
12744 else
12745 {
12746 varsign[cutindex] = +1;
12747 selectedbounds[cutindex] = SCIP_BOUNDTYPE_LOWER;
12748 }
12749 }
12750 else
12751 {
12752 /* For explicit integers, we have no restrictions. */
12753 SCIP_CALL( determineBestBounds(scip, data->vars[v], sol, data, boundswitch, usevbds, allowlocal, FALSE, FALSE,
12754 NULL, NULL, bestlbs + cutindex, bestubs + cutindex,
12755 bestlbtypes + cutindex, bestubtypes + cutindex, selectedbounds + cutindex, freevariable) );
12756
12757 if( *freevariable)
12758 goto TERMINATE;
12759 }
12760
12761 data->cutinds[cutindex] = v;
12762 ++data->ncutinds;
12763
12764 ++i;
12765 }
12766
12767 /* perform bound substitution for all nonzeros in the section */
12768 for( i = cutindsstart; i < data->ncutinds; ++i )
12769 {
12770 SCIP_Real bestbnd;
12771 int v = data->cutinds[i];
12772
12773 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
12774 {
12775 assert(!SCIPisInfinity(scip, -bestlbs[i]));
12776
12777 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
12778 boundtype[i] = bestlbtypes[i];
12779 varsign[i] = +1;
12780 bestbnd = bestlbs[i];
12781 }
12782 else
12783 {
12784 assert(!SCIPisInfinity(scip, bestubs[i]));
12785
12786 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
12787 boundtype[i] = bestubtypes[i];
12788 varsign[i] = -1;
12789 bestbnd = bestubs[i];
12790 }
12791
12792 doMIRBoundSubstitution(scip, data, varsign[i], boundtype[i], bestbnd, v, localbdsused);
12793 }
12794 }
12795
12796 /* relax rhs to zero if it is close to */
12797 if( QUAD_TO_DBL(data->cutrhs) < 0.0 && QUAD_TO_DBL(data->cutrhs) >= -SCIPepsilon(scip) )
12798 QUAD_ASSIGN(data->cutrhs, 0.0);
12799
12800 TERMINATE:
12801
12802 /* If we terminate early, we need to make sure all the zeros in the cut coefficient array are cancelled */
12803 if( *freevariable )
12804 {
12805 int j;
12806 int k;
12807
12808 data->ncutinds = 0;
12809 for( j = 0; j < NSECTIONS; ++j )
12810 {
12811 int* indexlist = data->secindices[j];
12812 for( k = 0; k < data->secnnz[j]; ++k )
12813 {
12814 data->cutinds[data->ncutinds] = indexlist[k];
12815 ++data->ncutinds;
12816 }
12817 }
12818 }
12819
12820 /*free temporary memory */
12821 SCIPfreeBufferArray(scip, &selectedbounds);
12822 SCIPfreeBufferArray(scip, &bestubtypes);
12823 SCIPfreeBufferArray(scip, &bestlbtypes);
12824 SCIPfreeBufferArray(scip, &bestubs);
12825 SCIPfreeBufferArray(scip, &bestlbs);
12826
12827 return SCIP_OKAY;
12828}
12829
12830/** Calculate fractionalities \f$ f_0 := b - down(b) \f$, \f$ f_j := a^\prime_j - down(a^\prime_j) \f$,
12831 * 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
12832 * 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$
12833 * and derive strong CG cut \f$ \tilde{a} x^\prime \leq down(b) \f$
12834 * \f[
12835 * \begin{array}{rll}
12836 * integers : & \tilde{a}_j = down(a^\prime_j) &, if \qquad f_j \leq f_0 \\
12837 * & \tilde{a}_j = down(a^\prime_j) + p_j/(k + 1) &, if \qquad f_j > f_0 \\
12838 * continuous:& \tilde{a}_j = 0 &, if \qquad a^\prime_j \geq 0 \\
12839 * & \mbox{no strong CG cut found} &, if \qquad a^\prime_j < 0
12840 * \end{array}
12841 * \f]
12842 *
12843 * Transform inequality back to \f$ \hat{a}*x <= rhs \f$:
12844 *
12845 * (lb or ub):
12846 * \f[
12847 * \begin{array}{lllll}
12848 * 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} \\
12849 * 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}
12850 * \end{array}
12851 * \f]
12852 * \f[
12853 * and move the constant terms
12854 * \begin{array}{rl}
12855 * -\tilde{a}_j * lb_j == -\hat{a}_j * lb_j, & \mbox{or} \\
12856 * \tilde{a}_j * ub_j == -\hat{a}_j * ub_j &
12857 * \end{array}
12858 * \f]
12859 * to the rhs.
12860 *
12861 * (vlb or vub):
12862 * \f[
12863 * \begin{array}{lllll}
12864 * 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)} \\
12865 * 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)}
12866 * \end{array}
12867 * \f]
12868 * move the constant terms
12869 * \f[
12870 * \begin{array}{rl}
12871 * -\tilde{a}_j * dl_j == -\hat{a}_j * dl_j,& \mbox{or} \\
12872 * \tilde{a}_j * du_j == -\hat{a}_j * du_j &
12873 * \end{array}
12874 * \f]
12875 * to the rhs, and update the VB variable coefficients:
12876 * \f[
12877 * \begin{array}{ll}
12878 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j * bl_j == \hat{a}_{zl_j} - \hat{a}_j * bl_j,& \mbox{or} \\
12879 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j * bu_j == \hat{a}_{zu_j} - \hat{a}_j * bu_j &
12880 * \end{array}
12881 * \f]
12882 */
12883static
12885 SCIP* scip, /**< SCIP datastructure */
12886 MIR_DATA* data, /**< the MIR data structure for this cut */
12887 int* varsign, /**< stores the sign of the transformed variable in summation */
12888 int* boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub)*/
12889 QUAD(SCIP_Real f0), /**< fractional value of rhs */
12890 SCIP_Real k /**< factor to strengthen strongcg cut */
12891 )
12892{
12893 SCIP_Real QUAD(tmp);
12894 SCIP_Real QUAD(onedivoneminusf0);
12895 int cutindex;
12896 int s;
12897 int i;
12898
12899 assert(data != NULL);
12900 assert(boundtype != NULL);
12901 assert(varsign != NULL);
12902 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
12903
12904 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
12905 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
12906
12907 /* Loop backwards through the sections, so that the reversing of varbound substitutions does not prematurely effect
12908 * the coefficients of variables in other sections, because the section index of a variable bound must always be
12909 * higher than that of the bounded variable. */
12910 cutindex = data->ncutinds - 1;
12911 for( s = NSECTIONS - 1; s >= 0; --s )
12912 {
12913 int* indices = data->secindices[s];
12914 int nnz = data->secnnz[s];
12915 SCIP_Bool enfintegral = data->isenfint[s];
12916 SCIP_Bool implintegral = data->isimplint[s];
12917
12918 /* iterate backwards over indices in section, so we can easily shrink the section if we find zeros */
12919 for( i = nnz - 1; i >= 0 ; --i )
12920 {
12921 SCIP_Real QUAD(cutaj);
12922 SCIP_Real QUAD(aj);
12923 SCIP_VAR* var;
12924 int v = indices[i];
12925 int sign;
12926 int type;
12927
12928 assert(0 <= v && v < data->nvars);
12929 assert(data->cutinds[cutindex] == v);
12930 sign = varsign[cutindex];
12931 assert(sign == +1 || sign == -1);
12932 type = boundtype[cutindex];
12933
12934 --cutindex;
12935
12936 var = data->vars[v];
12937 assert(var != NULL);
12938 assert(SCIPvarGetProbindex(var) == v );
12939
12940 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
12941
12942 if( enfintegral || implintegral )
12943 {
12944 /* Variable is integral */
12945 SCIP_Real QUAD(downaj);
12946 SCIP_Real QUAD(fj);
12947
12948 /* calculate the coefficient in the retransformed cut */
12949 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
12950 QUAD_SCALE(aj, sign);
12951 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
12952 SCIPquadprecSumQQ(fj, aj, -downaj);
12953 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
12954
12955 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
12956 QUAD_ASSIGN_Q(cutaj, downaj); /* a_j */
12957 else
12958 {
12959 SCIP_Real pj;
12960
12961 SCIPquadprecSumQQ(cutaj, fj, -f0);
12962 SCIPquadprecProdQD(cutaj, cutaj, k);
12963 SCIPquadprecProdQQ(cutaj, cutaj, onedivoneminusf0);
12964 pj = SCIPceil(scip, QUAD_TO_DBL(cutaj));
12965 assert(pj >= 0); /* should be >= 1, but due to rounding bias can be 0 if fj is almost equal to f0 */
12966 assert(pj <= k);
12967 SCIPquadprecDivDD(cutaj, pj, k + 1.0);
12968 SCIPquadprecSumQQ(cutaj, cutaj, downaj);
12969 }
12970
12971 QUAD_SCALE(cutaj, sign);
12972 }
12973 else
12974 {
12975 /* Variable is continuous; must always be positive in strongcg cut. It will be automatically deleted. */
12977 assert(QUAD_TO_DBL(aj) * sign >= 0.0);
12978 QUAD_ASSIGN(cutaj, 0.0);
12979 }
12980
12981 /* remove coefficient from cut if it becomes zero */
12982 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
12983 {
12984 QUAD_ASSIGN(cutaj, 0.0);
12985 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
12986 --data->totalnnz;
12987 --data->secnnz[s];
12988 indices[i] = indices[data->secnnz[s]];
12989 continue;
12990 }
12991
12992 /* store the updated coefficient */
12993 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
12994
12995 /* undo bound transformations. */
12996 if( type < 0 )
12997 {
12998 /* standard bound */
12999 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
13000 if( sign == +1 )
13001 {
13002 /* lower bound was used */
13003 if( type == -1 )
13004 {
13005 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
13006 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
13007 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13008 }
13009 else
13010 {
13011 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
13012 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
13013 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13014 }
13015 }
13016 else
13017 {
13018 /* upper bound was used */
13019 if( type == -1 )
13020 {
13021 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
13022 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
13023 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13024 }
13025 else
13026 {
13027 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
13028 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
13029 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13030 }
13031 }
13032 }
13033 else
13034 {
13035 /* variable bound */
13036 SCIP_VAR** vbz;
13037 SCIP_Real* vbb;
13038 SCIP_Real* vbd;
13039 SCIP_Real QUAD(zcoef);
13040 int vbidx;
13041 int zidx;
13042
13043 /* variable bound */
13044 vbidx = type;
13045
13046 /* change mirrhs and cutaj of integer variable z_j of variable bound */
13047 if( sign == +1 )
13048 {
13049 /* variable lower bound was used */
13050 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
13051 vbz = SCIPvarGetVlbVars(var);
13052 vbb = SCIPvarGetVlbCoefs(var);
13053 vbd = SCIPvarGetVlbConstants(var);
13054 }
13055 else
13056 {
13057 /* variable upper bound was used */
13058 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
13059 vbz = SCIPvarGetVubVars(var);
13060 vbb = SCIPvarGetVubCoefs(var);
13061 vbd = SCIPvarGetVubConstants(var);
13062 }
13063 assert(SCIPvarIsActive(vbz[vbidx]));
13064 zidx = SCIPvarGetProbindex(vbz[vbidx]);
13065 assert(varSection(data, zidx) > s);
13066
13067 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
13068 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
13069
13070 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
13071 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
13072
13073 /* update sparsity pattern */
13074 if( QUAD_HI(zcoef) == 0.0 )
13075 {
13076 int zsection = varSection(data, zidx);
13077 data->secindices[zsection][data->secnnz[zsection]] = zidx;
13078 ++data->secnnz[zsection];
13079 ++data->totalnnz;
13080 }
13081
13082 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
13083 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
13084 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
13085 assert(QUAD_HI(zcoef) != 0.0);
13086 }
13087 }
13088 }
13089
13090 /* Finally, store the relevant data in cutinds which is the array used by the other functions */
13091 data->ncutinds = 0;
13092 for( s = 0; s < NSECTIONS; ++s )
13093 {
13094 int* indices = data->secindices[s];
13095 int nnz = data->secnnz[s];
13096 for( i = 0; i < nnz; ++i )
13097 {
13098 data->cutinds[data->ncutinds] = indices[i];
13099 ++data->ncutinds;
13100 }
13101 }
13102
13103 return SCIP_OKAY;
13104}
13105
13106/** substitute aggregated slack variables:
13107 *
13108 * 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
13109 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r] \f$.
13110 *
13111 * Depending on the slack's type (integral or continuous), its coefficient in the cut calculates as follows:
13112 * \f[
13113 * \begin{array}{rll}
13114 * integers: & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & if \qquad f_r \leq f_0 \\
13115 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + p_r/(k + 1), & if \qquad f_r > f_0 \\
13116 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & if \qquad a^\prime_r \geq 0 \\
13117 * & \mbox{no strong CG cut found}, & if \qquad a^\prime_r < 0
13118 * \end{array}
13119 * \f]
13120 *
13121 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
13122 */
13123static
13125 SCIP* scip, /**< SCIP datastructure */
13126 SCIP_Real* weights, /**< row weights in row summation */
13127 int* slacksign, /**< stores the sign of the row's slack variable in summation */
13128 int* rowinds, /**< sparsity pattern of used rows */
13129 int nrowinds, /**< number of used rows */
13130 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
13131 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
13132 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
13133 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
13134 int* nnz, /**< number of non-zeros in cut */
13135 QUAD(SCIP_Real f0), /**< fractional value of rhs */
13136 SCIP_Real k /**< factor to strengthen strongcg cut */
13137 )
13138{ /*lint --e{715}*/
13139 SCIP_ROW** rows;
13140 SCIP_Real QUAD(onedivoneminusf0);
13141 int i;
13142
13143 assert(scip != NULL);
13144 assert(weights != NULL);
13145 assert(slacksign != NULL);
13146 assert(rowinds != NULL);
13147 assert(SCIPisPositive(scip, scale));
13148 assert(cutcoefs != NULL);
13149 assert(QUAD_HI(cutrhs) != NULL);
13150 assert(cutinds != NULL);
13151 assert(nnz != NULL);
13152 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
13153
13154 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
13155 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
13156
13157 rows = SCIPgetLPRows(scip);
13158 for( i = 0; i < nrowinds; i++ )
13159 {
13160 SCIP_ROW* row;
13161 SCIP_Real QUAD(ar);
13162 SCIP_Real QUAD(downar);
13163 SCIP_Real QUAD(cutar);
13164 SCIP_Real QUAD(fr);
13165 SCIP_Real mul;
13166 int r;
13167
13168 r = rowinds[i];
13169 assert(0 <= r && r < SCIPgetNLPRows(scip));
13170 assert(slacksign[i] == -1 || slacksign[i] == +1);
13171 assert(!SCIPisZero(scip, weights[i]));
13172
13173 row = rows[r];
13174 assert(row != NULL);
13175 assert(row->len == 0 || row->cols != NULL);
13176 assert(row->len == 0 || row->cols_index != NULL);
13177 assert(row->len == 0 || row->vals != NULL);
13178
13179 /* get the slack's coefficient a'_r in the aggregated row */
13180 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
13181
13182 /* calculate slack variable's coefficient a_r in the cut */
13183 if( row->integral )
13184 {
13185 /* slack variable is always integral */
13186 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
13187 SCIPquadprecSumQQ(fr, ar, -downar);
13188 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
13189
13190 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
13191 QUAD_ASSIGN_Q(cutar, downar); /* a_r */
13192 else
13193 {
13194 SCIP_Real pr;
13195
13196 SCIPquadprecSumQQ(cutar, fr, -f0);
13197 SCIPquadprecProdQD(cutar, cutar, k);
13198 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
13199 pr = SCIPceil(scip, QUAD_TO_DBL(cutar));
13200 assert(pr >= 0); /* should be >= 1, but due to rounding bias can be 0 if fr is almost equal to f0 */
13201 assert(pr <= k);
13202 SCIPquadprecDivDD(cutar, pr, k + 1.0);
13203 SCIPquadprecSumQQ(cutar, cutar, downar);
13204 }
13205 }
13206 else
13207 {
13208 /* slack variable is continuous: */
13209 assert(QUAD_TO_DBL(ar) >= 0.0);
13210 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
13211 }
13212
13213 /* if the coefficient was reduced to zero, ignore the slack variable */
13214 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
13215 continue;
13216
13217 /* depending on the slack's sign, we have
13218 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
13219 * substitute a_r * s_r by adding a_r times the slack's definition to the cut.
13220 */
13221 mul = -slacksign[i] * QUAD_TO_DBL(cutar);
13222
13223 /* add the slack's definition multiplied with a_j to the cut */
13224 SCIP_CALL( varVecAddScaledRowCoefsQuad(cutinds, cutcoefs, nnz, row, mul) );
13225
13226 /* move slack's constant to the right hand side */
13227 if( slacksign[i] == +1 )
13228 {
13229 SCIP_Real rhs;
13230
13231 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a_r * (rhs - c) to the right hand side */
13232 assert(!SCIPisInfinity(scip, row->rhs));
13233 rhs = row->rhs - row->constant;
13234 if( row->integral )
13235 {
13236 /* the right hand side was implicitly rounded down in row aggregation */
13237 rhs = SCIPfloor(scip, rhs);
13238 }
13239
13240 SCIPquadprecProdQD(cutar, cutar, rhs);
13241 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -cutar);
13242 }
13243 else
13244 {
13245 SCIP_Real lhs;
13246
13247 /* a*x + c - s == lhs => s == a*x + c - lhs: move a_r * (c - lhs) to the right hand side */
13248 assert(!SCIPisInfinity(scip, -row->lhs));
13249 lhs = row->lhs - row->constant;
13250 if( row->integral )
13251 {
13252 /* the left hand side was implicitly rounded up in row aggregation */
13253 lhs = SCIPceil(scip, lhs);
13254 }
13255
13256 SCIPquadprecProdQD(cutar, cutar, lhs);
13257 SCIPquadprecSumQQ(*cutrhs, *cutrhs, cutar);
13258 }
13259 }
13260
13261 /* relax rhs to zero, if it's very close to 0 */
13262 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
13263 QUAD_ASSIGN(*cutrhs, 0.0);
13264
13265 return SCIP_OKAY;
13266}
13267
13268
13269/** calculates a strong CG cut out of the weighted sum of LP rows given by an aggregation row; the
13270 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
13271 * participate in a strongcg cut
13272 *
13273 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
13274 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
13275 *
13276 * @pre This method can be called if @p scip is in one of the following stages:
13277 * - \ref SCIP_STAGE_SOLVING
13278 *
13279 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
13280 */
13282 SCIP* scip, /**< SCIP data structure */
13283 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
13284 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
13285 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
13286 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
13287 * type substitution is allowed. The indices are: 0: continuous,
13288 * 1: continuous implint., 2: integer implint, 3: binary implint,
13289 * 4: integer, 5: binary */
13290 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
13291 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce strong CG cut for */
13292 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce strong CG cut for */
13293 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
13294 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute a strong CG cut for */
13295 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
13296 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
13297 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
13298 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
13299 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
13300 int* cutrank, /**< pointer to return rank of generated cut */
13301 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
13302 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
13303 )
13304{
13305 int i;
13306 int nvars;
13307 int* varsign;
13308 int* boundtype;
13309 SCIP_Real QUAD(downrhs);
13310 SCIP_Real QUAD(f0);
13311 SCIP_Real QUAD(tmp);
13312 SCIP_Real large;
13313 SCIP_Real k;
13314 SCIP_Bool freevariable;
13315 SCIP_Bool localbdsused;
13316 MIR_DATA* data;
13317
13318 assert(scip != NULL);
13319 assert(aggrrow != NULL);
13320 assert(SCIPisPositive(scip, scale));
13321 assert(cutcoefs != NULL);
13322 assert(cutrhs != NULL);
13323 assert(cutinds != NULL);
13324 assert(success != NULL);
13325 assert(cutislocal != NULL);
13326
13327 SCIPdebugMsg(scip, "calculating strong CG cut (scale: %g)\n", scale);
13328
13329 *success = FALSE;
13330
13331 /* determine value from which fractionalities are no longer reliable within tolerance */
13333
13334 /* terminate if an integral slack fractionality is unreliable or a negative continuous slack variable is present */
13335 for( i = 0; i < aggrrow->nrows; ++i )
13336 {
13337 if( ( scip->lp->rows[aggrrow->rowsinds[i]]->integral && ABS(aggrrow->rowweights[i] * scale) > large )
13338 || ( !scip->lp->rows[aggrrow->rowsinds[i]]->integral && aggrrow->rowweights[i] * aggrrow->slacksign[i] < 0.0 ) )
13339 return SCIP_OKAY;
13340 }
13341
13342 /* allocate temporary memory */
13343 nvars = SCIPgetNVars(scip);
13344 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
13345 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
13346
13347 /* Initialize cut data */
13348 int l;
13349 int nnz;
13350
13351 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
13352
13353 SCIP_CALL( SCIPallocBuffer(scip, &data) );
13354
13355 nnz = aggrrow->nnz;
13356 data->totalnnz = nnz;
13357
13358 /* initialize sections */
13359 for( l = 0; l < NSECTIONS; ++l )
13360 {
13361 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
13362 data->secnnz[l] = 0;
13363 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
13364 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
13365 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
13366 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
13367 /* Use variable bounds for the sections specified by the user */
13368 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
13369 }
13370
13371 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
13372 data->vars = SCIPgetVars(scip);
13373 data->nvars = SCIPgetNVars(scip);
13374 data->nbinvars = SCIPgetNBinVars(scip);
13375 data->nintvars = SCIPgetNIntVars(scip);
13380
13382 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
13383
13384 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, scale);
13385
13386 if( nnz > 0 )
13387 {
13388 /* Initalize cut with the aggregation */
13389 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
13390
13391 for( l = 0; l < nnz; ++l )
13392 {
13393 SCIP_Real QUAD(coef);
13394 int m = aggrrow->inds[l];
13395
13396 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
13397
13398 SCIPquadprecProdQD(coef, coef, scale);
13399
13400 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
13401
13402 assert(QUAD_HI(coef) != 0.0);
13403 }
13404
13405 /* Sort the array by problem index and add the variables to their sections */
13406 SCIPsortDownInt(data->cutinds, nnz);
13407 for( l = 0; l < nnz; ++l )
13408 {
13409 int section = varSection(data, data->cutinds[l]);
13410 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
13411 ++data->secnnz[section];
13412 }
13413 }
13414
13415 data->ncutinds = 0;
13416 *cutislocal = aggrrow->local;
13417
13418 if( data->totalnnz > 0 )
13419 {
13420 int firstcontvar;
13421
13422 /* Transform equation a*x == b, lb <= x <= ub into standard form
13423 * a'*x' == b, 0 <= x' <= ub'.
13424 *
13425 * Transform variables (lb or ub):
13426 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
13427 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
13428 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
13429 *
13430 * Transform variables (vlb or vub):
13431 * 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.
13432 * 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.
13433 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
13434 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
13435 * a_{zu_j} := a_{zu_j} + a_j * bu_j
13436 */
13437 SCIP_CALL( cutsTransformStrongCG(scip, data, sol, boundswitch, allowlocal, varsign, boundtype, &freevariable, &localbdsused) );
13438
13439 if( freevariable )
13440 goto TERMINATE;
13441
13442 assert(allowlocal || !localbdsused);
13443 *cutislocal = *cutislocal || localbdsused;
13444
13445 firstcontvar = nvars - SCIPgetNContVars(scip);
13446
13447 /* terminate if an integral coefficient fractionality is unreliable */
13448 for( i = data->ncutinds - 1; i >= 0 && data->cutinds[i] < firstcontvar; --i )
13449 {
13450 SCIP_Real QUAD(coef);
13451
13452 QUAD_ARRAY_LOAD(coef, data->cutcoefs, data->cutinds[i]);
13453
13454 if( ABS(QUAD_TO_DBL(coef)) > large )
13455 goto TERMINATE;
13456 }
13457
13458 SCIPdebug(printCutQuad(scip, NULL, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
13459 }
13460
13461 /* terminate if the side fractionality is unreliable */
13462 if( ABS(QUAD_TO_DBL(data->cutrhs)) > large )
13463 goto TERMINATE;
13464
13465 /* Calculate
13466 * - fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j)
13467 * - integer k >= 1 with 1/(k + 1) <= f_0 < 1/k
13468 * (=> k = up(1/f_0) - 1)
13469 * - 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)
13470 * (=> p_j = up( (f_j - f_0)/((1 - f_0)/k) ))
13471 * and derive strong CG cut
13472 * a~*x' <= (k+1) * down(b)
13473 * integers : a~_j = down(a'_j) , if f_j <= f_0
13474 * a~_j = down(a'_j) + p_j/(k + 1) , if f_j > f_0
13475 * continuous: a~_j = 0 , if a'_j >= 0
13476 * no strong CG cut found , if a'_j < 0
13477 *
13478 * Transform inequality back to a^*x <= rhs:
13479 *
13480 * (lb or ub):
13481 * 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
13482 * 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
13483 * and move the constant terms
13484 * -a~_j * lb_j == -a^_j * lb_j, or
13485 * a~_j * ub_j == -a^_j * ub_j
13486 * to the rhs.
13487 *
13488 * (vlb or vub):
13489 * 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)
13490 * 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)
13491 * move the constant terms
13492 * -a~_j * dl_j == -a^_j * dl_j, or
13493 * a~_j * du_j == -a^_j * du_j
13494 * to the rhs, and update the VB variable coefficients:
13495 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
13496 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
13497 */
13498 SCIPquadprecEpsFloorQ(downrhs, data->cutrhs, SCIPepsilon(scip)); /*lint !e666*/
13499 SCIPquadprecSumQQ(f0, data->cutrhs, -downrhs);
13500 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
13501
13502 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
13503 goto TERMINATE;
13504
13505 /* renormalize the f0 value */
13506 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
13507
13508 SCIPquadprecDivDQ(tmp, 1.0, f0);
13509 SCIPquadprecSumQD(tmp, tmp, -1.0);
13510 k = SCIPceil(scip, QUAD_TO_DBL(tmp));
13511 QUAD_ASSIGN_Q(data->cutrhs, downrhs);
13512
13513 if( data->totalnnz > 0 )
13514 {
13515 SCIP_CALL( cutsRoundStrongCG(scip, data, varsign, boundtype, QUAD(f0), k) );
13516 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
13517 }
13518
13519 /* substitute aggregated slack variables:
13520 *
13521 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
13522 * variable only appears in its own row:
13523 * a'_r = scale * weight[r] * slacksign[r].
13524 *
13525 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
13526 * integers : a_r = a~_r = (k + 1) * down(a'_r) , if f_r <= f0
13527 * a_r = a~_r = (k + 1) * down(a'_r) + p_r , if f_r > f0
13528 * continuous: a_r = a~_r = 0 , if a'_r >= 0
13529 * a_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
13530 *
13531 * Substitute a_r * s_r by adding a_r times the slack's definition to the cut.
13532 */
13533 SCIP_CALL( cutsSubstituteStrongCG(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
13534 aggrrow->nrows, scale, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds, QUAD(f0), k) );
13535 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
13536
13537 /* remove all nearly-zero coefficients from strong CG row and relax the right hand side correspondingly in order to
13538 * prevent numerical rounding errors
13539 */
13540 if( postprocess )
13541 {
13542 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, data->cutinds, data->cutcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
13543 }
13544 else
13545 {
13546 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds);
13547 }
13548 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
13549
13550 if( *success )
13551 {
13552 *cutrhs = QUAD_TO_DBL(data->cutrhs);
13553 *cutnnz = data->ncutinds;
13554
13555 /* store cut in given array in sparse representation and clean buffer array */
13556 for( i = 0; i < *cutnnz; ++i )
13557 {
13558 SCIP_Real QUAD(coef);
13559 int j = data->cutinds[i];
13560
13561 QUAD_ARRAY_LOAD(coef, data->cutcoefs, j);
13562 assert(QUAD_HI(coef) != 0.0);
13563
13564 cutcoefs[i] = QUAD_TO_DBL(coef);
13565 cutinds[i] = j;
13566 QUAD_ASSIGN(coef, 0.0);
13567 QUAD_ARRAY_STORE(data->cutcoefs, j, coef);
13568 }
13569
13570 if( cutefficacy != NULL )
13571 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
13572
13573 if( cutrank != NULL )
13574 *cutrank = aggrrow->rank + 1;
13575 }
13576
13577 TERMINATE:
13578
13579 /* if we aborted early the temporary coefficients need to be cleaned */
13580 if( !(*success) )
13581 {
13582 QUAD_ASSIGN(tmp, 0.0);
13583
13584 for( i = 0; i < data->ncutinds; ++i )
13585 {
13586 QUAD_ARRAY_STORE(data->cutcoefs, data->cutinds[i], tmp);
13587 }
13588 }
13589
13590 if( data->cutinds != NULL )
13592
13593 if( data->cutcoefs != NULL )
13595
13596 for( int s = NSECTIONS - 1; s >= 0; --s )
13597 {
13599 }
13600
13601 SCIPfreeBuffer(scip, &data);
13602
13603 /* free temporary memory */
13604 SCIPfreeBufferArray(scip, &boundtype);
13605 SCIPfreeBufferArray(scip, &varsign);
13606
13607 return SCIP_OKAY;
13608}
SCIP_CERTIFICATE * SCIPgetCertificate(SCIP *scip)
methods for certificate output
SCIP_VAR * h
Definition: circlepacking.c:68
SCIP_Real * r
Definition: circlepacking.c:59
SCIP_VAR ** x
Definition: circlepacking.c:63
#define MAXDNOM
Definition: cons_linear.c:166
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:8257
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:5872
struct MIR_Data MIR_DATA
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:4561
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:4164
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:352
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:5261
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:12054
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:3888
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:11769
static SCIP_Bool removeZerosSafely(SCIP *scip, SCIP_Real minval, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz)
Definition: cuts.c:727
static SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
Definition: cuts.c:1007
static SCIP_Real calcEfficacyDenseStorageQuad(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:650
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:822
static SCIP_RETCODE cutsRoundStrongCG(SCIP *scip, MIR_DATA *data, int *varsign, int *boundtype, QUAD(SCIP_Real f0), SCIP_Real k)
Definition: cuts.c:12884
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:4233
static SCIP_RETCODE cutsRoundMIR(SCIP *scip, MIR_DATA *data, int *RESTRICT varsign, int *RESTRICT boundtype, QUAD(SCIP_Real f0))
Definition: cuts.c:6710
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:13124
static SCIP_RETCODE computeLiftingData(SCIP *scip, SNF_RELAXATION *snf, int *transvarflowcoverstatus, SCIP_Real lambda, LIFTINGDATA *liftingdata, SCIP_Bool *valid)
Definition: cuts.c:11221
static void doMIRBoundSubstitution(SCIP *scip, MIR_DATA *data, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition: cuts.c:5009
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:9190
static SCIP_RETCODE getFlowCover(SCIP *scip, SNF_RELAXATION *snf, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, SCIP_Real *lambda, SCIP_Bool *found)
Definition: cuts.c:10833
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:9319
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:12170
static SCIP_Bool chgCoeffWithBound(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
Definition: cuts.c:1052
static SCIP_Bool chgQuadCoeffWithBound(SCIP *scip, SCIP_VAR *var, QUAD(SCIP_Real oldcoeff), SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
Definition: cuts.c:1097
#define MAXBOUND
Definition: cuts.c:9142
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:1585
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:4498
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:5543
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:9627
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:3822
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:7637
static int varSection(MIR_DATA *data, int probindex)
Definition: cuts.c:4124
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:5180
static void destroyLiftingData(SCIP *scip, LIFTINGDATA *liftingdata)
Definition: cuts.c:11351
static void performBoundSubstitutionSimpleSafely(SCIP *scip, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition: cuts.c:5146
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:4626
static SCIP_RETCODE varVecAddScaledRowCoefsQuad(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:240
static SCIP_Real calcEfficacyNormQuad(SCIP *scip, SCIP_Real *vals, int *inds, int nnz)
Definition: cuts.c:517
#define NSECTIONS
Definition: cuts.c:4088
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:2103
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:4803
#define NONZERO(x)
Definition: cuts.c:189
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:915
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:10222
static SCIP_Real calcEfficacyDenseStorage(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:579
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:9447
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:3753
static void destroySNFRelaxation(SCIP *scip, SNF_RELAXATION *snf)
Definition: cuts.c:10202
static SCIP_RETCODE allocSNFRelaxation(SCIP *scip, SNF_RELAXATION *snf, int nvars)
Definition: cuts.c:10181
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:3371
static SCIP_Bool chgCoeffWithBoundSafely(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal, SCIP_Real *cutrhs)
Definition: cuts.c:1142
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:6953
static SCIP_Real calcEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:452
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:10317
#define MAXCMIRSCALE
Definition: cuts.c:4079
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:11364
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:12597
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:1658
static void getAlphaAndBeta(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real vubcoef, int *alpha, SCIP_Real *beta)
Definition: cuts.c:11184
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, QUAD(SCIP_Real f0))
Definition: cuts.c:7477
#define MAXABSVBCOEF
Definition: cuts.c:9141
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:3257
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:4299
static SCIP_RETCODE varVecAddScaledRowCoefsQuadScale(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, QUAD(SCIP_Real scale))
Definition: cuts.c:287
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:5099
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:5320
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:1207
static SCIP_Real evaluateLiftingFunction(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real x)
Definition: cuts.c:11100
static SCIP_RETCODE varVecAddScaledRowCoefs(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:195
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:4715
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, QUAD(SCIP_Real *coverweight))
Definition: cuts.c:11963
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:248
#define COPYSIGN
Definition: def.h:239
#define SCIP_Longint
Definition: def.h:141
#define SCIP_UNUSED(x)
Definition: def.h:409
#define EPSISINT(x, eps)
Definition: def.h:195
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define ABS(x)
Definition: def.h:216
#define EPSFRAC(x, eps)
Definition: def.h:194
#define SQR(x)
Definition: def.h:199
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_CALL_ABORT(x)
Definition: def.h:334
#define RESTRICT
Definition: def.h:260
#define SCIPABORT()
Definition: def.h:327
#define SCIP_REAL_MIN
Definition: def.h:159
#define EPSFLOOR(x, eps)
Definition: def.h:191
#define REALABS(x)
Definition: def.h:182
#define EPSZ(x, eps)
Definition: def.h:188
#define SCIP_CALL(x)
Definition: def.h:355
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
Definition: scip_message.h:79
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
#define SCIPdebugMsg
Definition: scip_message.h:78
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:3008
SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
Definition: cuts.c:4005
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:8339
SCIP_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:7923
int SCIPaggrRowGetRank(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:4048
SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
Definition: cuts.c:2466
void SCIPaggrRowClearSafely(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:3196
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:2668
SCIP_RETCODE SCIPaggrRowAddRowSafely(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype, SCIP_Bool *success)
Definition: cuts.c:2887
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:12270
void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:3218
SCIP_RETCODE SCIPaggrRowCopy(SCIP *scip, SCIP_AGGRROW **aggrrow, SCIP_AGGRROW *source)
Definition: cuts.c:2758
SCIP_Bool SCIPaggrRowIsLocal(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:4058
SCIP_Real SCIPaggrRowGetRhs(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:4068
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:3973
SCIP_RETCODE SCIPaggrRowAddCustomCons(SCIP *scip, SCIP_AGGRROW *aggrrow, int *inds, SCIP_Real *vals, int len, SCIP_Real rhs, SCIP_Real weight, int rank, SCIP_Bool local)
Definition: cuts.c:3143
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:13281
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:2700
int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:4028
void SCIPaggrRowPrint(SCIP *scip, SCIP_AGGRROW *aggrrow, FILE *file)
Definition: cuts.c:2721
void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool useglbbounds, SCIP_Bool *valid)
Definition: cuts.c:3949
SCIP_Real * SCIPaggrRowGetRowWeights(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:3994
int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:4038
SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
Definition: cuts.c:2804
int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:3983
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:3523
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:3067
SCIP_RETCODE SCIPcalcFlowCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:11645
SCIP_Real SCIPaggrRowCalcEfficacyNorm(SCIP *scip, SCIP_AGGRROW *aggrrow)
Definition: cuts.c:3243
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
Definition: intervalarith.h:65
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
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)
Definition: rational.cpp:1576
void SCIPrationalMult(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
Definition: rational.cpp:1066
void SCIPrationalInvert(SCIP_RATIONAL *res, SCIP_RATIONAL *op)
Definition: rational.cpp:1323
SCIP_Real SCIPrationalGetReal(SCIP_RATIONAL *rational)
Definition: rational.cpp:2085
void SCIPrationalDiv(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
Definition: rational.cpp:1132
void SCIPrationalSetReal(SCIP_RATIONAL *res, SCIP_Real real)
Definition: rational.cpp:603
void SCIPrationalFreeBuffer(BMS_BUFMEM *bufmem, SCIP_RATIONAL **rational)
Definition: rational.cpp:473
void SCIPrationalDiff(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
Definition: rational.cpp:983
SCIP_Bool SCIPrationalIsPositive(SCIP_RATIONAL *rational)
Definition: rational.cpp:1640
SCIP_RETCODE SCIPrationalCreateBuffer(BMS_BUFMEM *bufmem, SCIP_RATIONAL **rational)
Definition: rational.cpp:123
SCIP_Bool SCIPrationalIsZero(SCIP_RATIONAL *rational)
Definition: rational.cpp:1624
void SCIPrationalSetRational(SCIP_RATIONAL *res, SCIP_RATIONAL *src)
Definition: rational.cpp:569
SCIP_Bool SCIPrationalIsGEReal(SCIP_RATIONAL *rat, SCIP_Real real)
Definition: rational.cpp:1606
SCIP_Bool SCIPrationalIsNegative(SCIP_RATIONAL *rational)
Definition: rational.cpp:1650
void SCIPrationalDiffReal(SCIP_RATIONAL *res, SCIP_RATIONAL *rat, SCIP_Real real)
Definition: rational.cpp:1009
SCIP_Real SCIPrationalRoundReal(SCIP_RATIONAL *rational, SCIP_ROUNDMODE_RAT roundmode)
Definition: rational.cpp:2110
SCIP_Bool SCIPrationalIsEQReal(SCIP_RATIONAL *rat, SCIP_Real real)
Definition: rational.cpp:1437
void SCIPrationalMultReal(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_Real op2)
Definition: rational.cpp:1097
SCIP_Bool SCIPrationalIsLE(SCIP_RATIONAL *rat1, SCIP_RATIONAL *rat2)
Definition: rational.cpp:1521
void SCIPrationalAddReal(SCIP_RATIONAL *res, SCIP_RATIONAL *rat, SCIP_Real real)
Definition: rational.cpp:961
void SCIPrationalAddProdReal(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_Real op2)
Definition: rational.cpp:1210
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:1765
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:24482
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:24504
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:23642
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
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:23662
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:24514
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:24524
SCIP_RATIONAL * SCIPvarGetUbLocalExact(SCIP_VAR *var)
Definition: var.c:24278
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
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:24664
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_RATIONAL * SCIPvarGetLbGlobalExact(SCIP_VAR *var)
Definition: var.c:24130
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:24494
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
SCIP_RATIONAL * SCIPvarGetLbLocalExact(SCIP_VAR *var)
Definition: var.c:24244
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:24556
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:24536
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:24546
SCIP_RATIONAL * SCIPvarGetUbGlobalExact(SCIP_VAR *var)
Definition: var.c:24152
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)
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 (weighted) 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:9149
SCIP_Real lambda
Definition: cuts.c:9160
int r
Definition: cuts.c:9156
int t
Definition: cuts.c:9157
SCIP_Real * m
Definition: cuts.c:9150
SCIP_Real d2
Definition: cuts.c:9159
SCIP_Real mp
Definition: cuts.c:9161
SCIP_Real ml
Definition: cuts.c:9162
SCIP_Real d1
Definition: cuts.c:9158
SCIP_VAR ** vars
Definition: cuts.c:4103
int usevbds[NSECTIONS]
Definition: cuts.c:4100
SCIP_Real QUAD(cutrhs)
SCIP_Bool isenfint[NSECTIONS]
Definition: cuts.c:4096
int * cutinds
Definition: cuts.c:4115
int nvars
Definition: cuts.c:4104
int nbinimplvars
Definition: cuts.c:4107
int nintvars
Definition: cuts.c:4106
SCIP_Bool isimplint[NSECTIONS]
Definition: cuts.c:4097
SCIP_Real * cutcoefs
Definition: cuts.c:4112
int nintimplvars
Definition: cuts.c:4108
int ncutinds
Definition: cuts.c:4116
int totalnnz
Definition: cuts.c:4092
int ncontvars
Definition: cuts.c:4110
int ncontimplvars
Definition: cuts.c:4109
int nbinvars
Definition: cuts.c:4105
int * secindices[NSECTIONS]
Definition: cuts.c:4093
int secnnz[NSECTIONS]
Definition: cuts.c:4094
SCIP_Real * vals
Definition: struct_cuts.h:42
SCIP_Real * rowweights
Definition: struct_cuts.h:46
int * rowsinds
Definition: struct_cuts.h:44
SCIP_Bool local
Definition: struct_cuts.h:52
int * slacksign
Definition: struct_cuts.h:45
SCIP_Longint nmirinfos
SCIP_MIRINFO ** mirinfo
SCIP_Longint naggrinfos
SCIP_AGGREGATIONINFO ** aggrinfo
SCIP_VAR * var
Definition: struct_lp.h:162
int var_probindex
Definition: struct_lp.h:180
SCIP_Real sup
Definition: intervalarith.h:57
SCIP_Real inf
Definition: intervalarith.h:56
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
int rank
Definition: struct_lp.h:253
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
int len
Definition: struct_lp.h:239
SCIP_Real * transbinvarsolvals
Definition: cuts.c:9170
int * transvarcoefs
Definition: cuts.c:9169
SCIP_Real * transcontvarsolvals
Definition: cuts.c:9171
SCIP_Real * aggrcoefsbin
Definition: cuts.c:9177
int * origcontvars
Definition: cuts.c:9176
SCIP_Real transrhs
Definition: cuts.c:9174
int * origbinvars
Definition: cuts.c:9175
SCIP_Real * aggrconstants
Definition: cuts.c:9181
SCIP_Real * aggrcoefscont
Definition: cuts.c:9179
int ntransvars
Definition: cuts.c:9173
SCIP_Real * transvarvubcoefs
Definition: cuts.c:9172
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
@ 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
@ 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
@ SCIP_R_ROUND_UPWARDS
Definition: type_rational.h:58
@ SCIP_R_ROUND_DOWNWARDS
Definition: type_rational.h:57
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:65
@ SCIP_VARTYPE_CONTINUOUS
Definition: type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:64