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-2024 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*/
34
36#include "scip/cuts.h"
37#include "scip/dbldblarith.h"
38#include "scip/lp.h"
39#include "scip/pub_lp.h"
40#include "scip/pub_message.h"
41#include "scip/pub_misc.h"
43#include "scip/pub_misc_sort.h"
44#include "scip/pub_var.h"
45#include "scip/scip_cut.h"
46#include "scip/scip_lp.h"
47#include "scip/scip_mem.h"
48#include "scip/scip_message.h"
49#include "scip/scip_numerics.h"
50#include "scip/scip_prob.h"
51#include "scip/scip_sol.h"
53#include "scip/scip_var.h"
54#include "scip/struct_lp.h"
55#include "scip/struct_scip.h"
56#include "scip/struct_set.h"
57
58/* =========================================== general static functions =========================================== */
59#ifdef SCIP_DEBUG
60static
61void printCutQuad(
62 SCIP* scip, /**< SCIP data structure */
63 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
64 SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
65 QUAD(SCIP_Real cutrhs), /**< right hand side of the MIR row */
66 int* cutinds, /**< indices of problem variables for non-zero coefficients */
67 int cutnnz, /**< number of non-zeros in cut */
68 SCIP_Bool ignoresol,
69 SCIP_Bool islocal
70 )
71{
72 SCIP_Real QUAD(activity);
73 SCIP_VAR** vars;
74 int i;
75
76 assert(scip != NULL);
77 vars = SCIPgetVars(scip);
78
79 SCIPdebugMsg(scip, "CUT:");
80 QUAD_ASSIGN(activity, 0.0);
81 for( i = 0; i < cutnnz; ++i )
82 {
83 SCIP_Real QUAD(coef);
84
85 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
86
87 if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_BINARY )
88 SCIPdebugMsgPrint(scip, " %+g<%s>[B]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
89 else if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_INTEGER )
90 SCIPdebugMsgPrint(scip, " %+g<%s>[I]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
91 else
92 SCIPdebugMsgPrint(scip, " %+g<%s>[C]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
93
94 if( ! ignoresol )
95 {
96 SCIPquadprecProdQD(coef, coef, (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]])));
97 }
98 else
99 {
100 if( cutcoefs[i] > 0.0 )
101 {
102 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]])));
103 }
104 else
105 {
106 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]])));
107 }
108 }
109
110 SCIPquadprecSumQQ(activity, activity, coef);
111 }
112 SCIPdebugMsgPrint(scip, " <= %.6f (activity: %g)\n", QUAD_TO_DBL(cutrhs), QUAD_TO_DBL(activity));
113}
114#endif
115
116/** macro to make sure a value is not equal to zero, i.e. NONZERO(x) != 0.0
117 * will be TRUE for every x including 0.0
118 *
119 * To avoid branches it will add 1e-100 with the same sign as x to x which will
120 * be rounded away for any sane non-zero value but will make sure the value is
121 * never exactly 0.0.
122 */
123#define NONZERO(x) (COPYSIGN(1e-100, (x)) + (x))
124
125/** add a scaled row to a dense vector indexed over the problem variables and keep the
126 * index of non-zeros up-to-date
127 */
128static
130 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
131 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
132 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
133 SCIP_ROW* row, /**< row coefficients to add to variable vector */
134 SCIP_Real scale /**< scale for adding given row to variable vector */
135 )
136{
137 int i;
138
139 assert(inds != NULL);
140 assert(vals != NULL);
141 assert(nnz != NULL);
142 assert(row != NULL);
143
144 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
145 for( i = 0 ; i < row->len; ++i )
146 {
147 SCIP_Real val;
148 int probindex;
149
150 probindex = row->cols[i]->var_probindex;
151 val = vals[probindex];
152
153 if( val == 0.0 )
154 inds[(*nnz)++] = probindex;
155
156 val += row->vals[i] * scale;
157
158 /* the value must not be exactly zero due to sparsity pattern */
159 val = NONZERO(val);
160
161 assert(val != 0.0);
162 vals[probindex] = val;
163 }
164
165 return SCIP_OKAY;
166}
167
168/** add a scaled row to a dense vector indexed over the problem variables and keep the
169 * index of non-zeros up-to-date
170 *
171 * This is the quad precision version of varVecAddScaledRowCoefs().
172 */
173static
175 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
176 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
177 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
178 SCIP_ROW* row, /**< row coefficients to add to variable vector */
179 SCIP_Real scale /**< scale for adding given row to variable vector */
180 )
181{
182 int i;
183
184 assert(inds != NULL);
185 assert(vals != NULL);
186 assert(nnz != NULL);
187 assert(row != NULL);
188
189 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
190 for( i = 0 ; i < row->len; ++i )
191 {
192 SCIP_Real QUAD(scaledrowval);
193 SCIP_Real QUAD(val);
194 int probindex;
195
196 probindex = row->cols[i]->var_probindex;
197 QUAD_ARRAY_LOAD(val, vals, probindex);
198
199 if( QUAD_HI(val) == 0.0 )
200 inds[(*nnz)++] = probindex;
201
202 SCIPquadprecProdDD(scaledrowval, row->vals[i], scale);
203 SCIPquadprecSumQQ(val, val, scaledrowval);
204
205 /* the value must not be exactly zero due to sparsity pattern */
206 QUAD_HI(val) = NONZERO(QUAD_HI(val));
207 assert(QUAD_HI(val) != 0.0);
208
209 QUAD_ARRAY_STORE(vals, probindex, val);
210 }
211
212 return SCIP_OKAY;
213}
214
215/** add a scaled row to a dense vector indexed over the problem variables and keep the
216 * index of non-zeros up-to-date
217 *
218 * This is the quad precision version of varVecAddScaledRowCoefs() with a quad precision scaling factor.
219 */
220static
222 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
223 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
224 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
225 SCIP_ROW* row, /**< row coefficients to add to variable vector */
226 QUAD(SCIP_Real scale) /**< scale for adding given row to variable vector */
227 )
228{
229 int i;
230
231 assert(inds != NULL);
232 assert(vals != NULL);
233 assert(nnz != NULL);
234 assert(row != NULL);
235
236 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
237 for( i = 0 ; i < row->len; ++i )
238 {
239 SCIP_Real QUAD(val);
240 SCIP_Real QUAD(rowval);
241 int probindex;
242
243 probindex = row->cols[i]->var_probindex;
244 QUAD_ARRAY_LOAD(val, vals, probindex);
245
246 if( QUAD_HI(val) == 0.0 )
247 {
248 inds[(*nnz)++] = probindex;
249 SCIPquadprecProdQD(val, scale, row->vals[i]);
250 }
251 else
252 {
253 SCIPquadprecProdQD(rowval, scale, row->vals[i]);
254 SCIPquadprecSumQQ(val, val, rowval);
255 }
256
257 /* the value must not be exactly zero due to sparsity pattern */
258 QUAD_HI(val) = NONZERO(QUAD_HI(val));
259 assert(QUAD_HI(val) != 0.0);
260
261 QUAD_ARRAY_STORE(vals, probindex, val);
262 }
263
264 return SCIP_OKAY;
265}
266
267/** calculates the cut efficacy for the given solution */
268static
270 SCIP* scip, /**< SCIP data structure */
271 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
272 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
273 SCIP_Real cutrhs, /**< the right hand side of the cut */
274 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
275 int cutnnz /**< the number of non-zeros in the cut */
276 )
277{
278 SCIP_VAR** vars;
279 SCIP_Real norm = 0.0;
280 SCIP_Real activity = 0.0;
281 int i;
282
283 assert(scip != NULL);
284 assert(cutcoefs != NULL);
285 assert(cutinds != NULL);
286
287 vars = SCIPgetVars(scip);
288
289 switch( scip->set->sepa_efficacynorm )
290 {
291 case 'e':
292 for( i = 0; i < cutnnz; ++i )
293 {
294 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
295 norm += SQR(cutcoefs[i]);
296 }
297 norm = sqrt(norm);
298 break;
299 case 'm':
300 for( i = 0; i < cutnnz; ++i )
301 {
302 SCIP_Real absval;
303
304 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
305 absval = REALABS(cutcoefs[i]);
306 norm = MAX(norm, absval);
307 }
308 break;
309 case 's':
310 for( i = 0; i < cutnnz; ++i )
311 {
312 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
313 norm += REALABS(cutcoefs[i]);
314 }
315 break;
316 case 'd':
317 for( i = 0; i < cutnnz; ++i )
318 {
319 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
320 if( !SCIPisZero(scip, cutcoefs[i]) )
321 norm = 1.0;
322 }
323 break;
324 default:
325 SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", scip->set->sepa_efficacynorm);
326 assert(FALSE); /*lint !e506*/
327 }
328
329 return (activity - cutrhs) / MAX(1e-6, norm);
330}
331
332/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter */
333static
335 SCIP* scip, /**< SCIP data structure */
336 SCIP_Real* vals, /**< array of the non-zero coefficients in the vector; this is a quad precision array! */
337 int* inds, /**< array of the problem indices of variables with a non-zero coefficient in the vector */
338 int nnz /**< the number of non-zeros in the vector */
339 )
340{
341 SCIP_Real norm = 0.0;
342 SCIP_Real QUAD(coef);
343 int i;
344
345 assert(scip != NULL);
346 assert(scip->set != NULL);
347
348 switch( scip->set->sepa_efficacynorm )
349 {
350 case 'e':
351 for( i = 0; i < nnz; ++i )
352 {
353 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
354 norm += SQR(QUAD_TO_DBL(coef));
355 }
356 norm = sqrt(norm);
357 break;
358 case 'm':
359 for( i = 0; i < nnz; ++i )
360 {
361 SCIP_Real absval;
362 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
363
364 absval = REALABS(QUAD_TO_DBL(coef));
365 norm = MAX(norm, absval);
366 }
367 break;
368 case 's':
369 for( i = 0; i < nnz; ++i )
370 {
371 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
372 norm += REALABS(QUAD_TO_DBL(coef));
373 }
374 break;
375 case 'd':
376 for( i = 0; i < nnz; ++i )
377 {
378 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
379 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
380 {
381 norm = 1.0;
382 break;
383 }
384 }
385 break;
386 default:
387 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
388 assert(FALSE); /*lint !e506*/
389 }
390
391 return norm;
392}
393
394/** calculates the cut efficacy for the given solution; the cut coefs are stored densely and in quad precision */
395static
397 SCIP* scip, /**< SCIP data structure */
398 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
399 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
400 SCIP_Real cutrhs, /**< the right hand side of the cut */
401 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
402 int cutnnz /**< the number of non-zeros in the cut */
403 )
404{
405 SCIP_VAR** vars;
406 SCIP_Real norm = 0.0;
407 SCIP_Real activity = 0.0;
408 SCIP_Real QUAD(coef);
409 int i;
410
411 assert(scip != NULL);
412 assert(cutcoefs != NULL);
413 assert(cutinds != NULL);
414 assert(scip->set != NULL);
415
416 vars = SCIPgetVars(scip);
417
418 switch( scip->set->sepa_efficacynorm )
419 {
420 case 'e':
421 for( i = 0; i < cutnnz; ++i )
422 {
423 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
424 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
425 norm += SQR(QUAD_TO_DBL(coef));
426 }
427 norm = sqrt(norm);
428 break;
429 case 'm':
430 for( i = 0; i < cutnnz; ++i )
431 {
432 SCIP_Real absval;
433
434 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
435 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
436 absval = REALABS(QUAD_TO_DBL(coef));
437 norm = MAX(norm, absval);
438 }
439 break;
440 case 's':
441 for( i = 0; i < cutnnz; ++i )
442 {
443 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
444 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
445 norm += REALABS(QUAD_TO_DBL(coef));
446 }
447 break;
448 case 'd':
449 for( i = 0; i < cutnnz; ++i )
450 {
451 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
452 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
453 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
454 norm = 1.0;
455 }
456 break;
457 default:
458 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
459 assert(FALSE); /*lint !e506*/
460 }
461
462 return (activity - cutrhs) / MAX(1e-6, norm);
463}
464
465/** safely remove all items with |a_i| or |u_i - l_i| below the given value
466 *
467 * Returns TRUE if the cut became redundant.
468 * If it is a local cut, use local bounds, otherwise, use global bounds.
469 */
470static
472 SCIP* scip, /**< SCIP data structure */
473 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
474 SCIP_Bool cutislocal, /**< is the cut local? */
475 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
476 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
477 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
478 int* cutnnz /**< the number of non-zeros in the cut */
479 )
480{
481 int i;
482 SCIP_VAR** vars;
483
484 vars = SCIPgetVars(scip);
485
486 for( i = 0; i < *cutnnz; )
487 {
488 SCIP_Real QUAD(val);
489 SCIP_Real lb;
490 SCIP_Real ub;
491 int v;
492 SCIP_Bool isfixed;
493
494 v = cutinds[i];
495 QUAD_ARRAY_LOAD(val, cutcoefs, v);
496
497 if( cutislocal )
498 {
499 lb = SCIPvarGetLbLocal(vars[v]);
500 ub = SCIPvarGetUbLocal(vars[v]);
501 }
502 else
503 {
504 lb = SCIPvarGetLbGlobal(vars[v]);
505 ub = SCIPvarGetUbGlobal(vars[v]);
506 }
507
508 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
509 isfixed = TRUE;
510 else
511 isfixed = FALSE;
512
513 if( isfixed || EPSZ(QUAD_TO_DBL(val), minval) )
514 {
515 if( REALABS(QUAD_TO_DBL(val)) > QUAD_EPSILON )
516 {
517 /* adjust right hand side with max contribution */
518 if( QUAD_TO_DBL(val) < 0.0 )
519 {
520 if( SCIPisInfinity(scip, ub) )
521 return TRUE;
522 else
523 {
524 SCIPquadprecProdQD(val, val, ub);
525 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
526 }
527 }
528 else
529 {
530 if( SCIPisInfinity(scip, -lb) )
531 return TRUE;
532 else
533 {
534 SCIPquadprecProdQD(val, val, lb);
535 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
536 }
537 }
538 }
539
540 QUAD_ASSIGN(val, 0.0);
541 QUAD_ARRAY_STORE(cutcoefs, v, val);
542
543 /* remove non-zero entry */
544 --(*cutnnz);
545 cutinds[i] = cutinds[*cutnnz];
546 }
547 else
548 ++i;
549 }
550
551 /* relax rhs to 0, if it's very close to 0 */
552 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
553 QUAD_ASSIGN(*cutrhs, 0.0);
554
555 return FALSE;
556}
557
558/** safely remove all items with |a_i| or |u_i - l_i| below the given value
559 *
560 * Returns TRUE if the cut became redundant.
561 * If it is a local cut, use local bounds, otherwise, use global bounds.
562 */
563static
565 SCIP* scip, /**< SCIP data structure */
566 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
567 SCIP_Bool cutislocal, /**< is the cut local? */
568 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
569 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
570 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
571 int* cutnnz /**< the number of non-zeros in the cut */
572 )
573{
574 int i;
575 SCIP_VAR** vars;
576
577 vars = SCIPgetVars(scip);
578
579 /* loop over non-zeros and remove values below minval; values above QUAD_EPSILON are cancelled with their bound
580 * to avoid numerical rounding errors
581 */
582 for( i = 0; i < *cutnnz; )
583 {
584 SCIP_Real val;
585 SCIP_Real lb;
586 SCIP_Real ub;
587 int v;
588 SCIP_Bool isfixed;
589 SCIP_Real QUAD(quadprod);
590
591 v = cutinds[i];
592 val = cutcoefs[v];
593
594 if( cutislocal )
595 {
596 lb = SCIPvarGetLbLocal(vars[v]);
597 ub = SCIPvarGetUbLocal(vars[v]);
598 }
599 else
600 {
601 lb = SCIPvarGetLbGlobal(vars[v]);
602 ub = SCIPvarGetUbGlobal(vars[v]);
603 }
604
605 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
606 isfixed = TRUE;
607 else
608 isfixed = FALSE;
609
610 if( EPSZ(val, minval) || isfixed )
611 {
612 if( REALABS(val) > QUAD_EPSILON )
613 {
614 /* adjust left and right hand sides with max contribution */
615 if( val < 0.0 )
616 {
617 if( SCIPisInfinity(scip, ub) )
618 return TRUE;
619 else
620 {
621 SCIPquadprecProdDD(quadprod, -val, ub);
622 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
623 }
624 }
625 else
626 {
627 if( SCIPisInfinity(scip, -lb) )
628 return TRUE;
629 else
630 {
631 SCIPquadprecProdDD(quadprod, -val, lb);
632 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
633 }
634 }
635 }
636
637 cutcoefs[v] = 0.0;
638
639 /* remove non-zero entry */
640 --(*cutnnz);
641 cutinds[i] = cutinds[*cutnnz];
642 }
643 else
644 ++i;
645 }
646
647 /* relax rhs to 0, if it's very close to 0 */
648 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
649 QUAD_ASSIGN(*cutrhs, 0.0);
650
651 return FALSE;
652}
653
654/** compare absolute values of coefficients in quad precision */
655static
656SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
657{
658 SCIP_Real abscoef1;
659 SCIP_Real abscoef2;
660 SCIP_Real QUAD(coef1);
661 SCIP_Real QUAD(coef2);
662 SCIP_Real* coefs = (SCIP_Real*) dataptr;
663
664 QUAD_ARRAY_LOAD(coef1, coefs, ind1);
665 QUAD_ARRAY_LOAD(coef2, coefs, ind2);
666
667 abscoef1 = REALABS(QUAD_TO_DBL(coef1));
668 abscoef2 = REALABS(QUAD_TO_DBL(coef2));
669
670 if( abscoef1 < abscoef2 )
671 return -1;
672 if( abscoef2 < abscoef1 )
673 return 1;
674
675 return 0;
676}
677
678/** compare absolute values of coefficients */
679static
680SCIP_DECL_SORTINDCOMP(compareAbsCoefs)
681{
682 SCIP_Real abscoef1;
683 SCIP_Real abscoef2;
684 SCIP_Real* coefs = (SCIP_Real*) dataptr;
685
686 abscoef1 = REALABS(coefs[ind1]);
687 abscoef2 = REALABS(coefs[ind2]);
688
689 if( abscoef1 < abscoef2 )
690 return -1;
691 if( abscoef2 < abscoef1 )
692 return 1;
693
694 return 0;
695}
696
697/** change given coefficient to new given value, adjust right hand side using the variables bound;
698 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
699 */
700static
702 SCIP* scip, /**< SCIP data structure */
703 SCIP_VAR* var, /**< variable the coefficient belongs to */
704 SCIP_Real oldcoeff, /**< old coefficient value */
705 SCIP_Real newcoeff, /**< new coefficient value */
706 SCIP_Bool cutislocal, /**< is the cut local? */
707 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
708 )
709{
710 SCIP_Real QUAD(delta);
711
712 SCIPquadprecSumDD(delta, newcoeff, -oldcoeff);
713
714 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
715 {
716 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
717
718 if( SCIPisInfinity(scip, ub) )
719 return TRUE;
720 else
721 {
722 SCIPquadprecProdQD(delta, delta, ub);
723 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
724 }
725 }
726 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
727 {
728 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
729
730 if( SCIPisInfinity(scip, -lb) )
731 return TRUE;
732 else
733 {
734 SCIPquadprecProdQD(delta, delta, lb);
735 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
736 }
737 }
738
739 return FALSE;
740}
741
742/** change given (quad) coefficient to new given value, adjust right hand side using the variables bound;
743 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
744 */
745static
747 SCIP* scip, /**< SCIP data structure */
748 SCIP_VAR* var, /**< variable the coefficient belongs to */
749 QUAD(SCIP_Real oldcoeff), /**< old coefficient value */
750 SCIP_Real newcoeff, /**< new coefficient value */
751 SCIP_Bool cutislocal, /**< is the cut local? */
752 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
753 )
754{
755 SCIP_Real QUAD(delta);
756
757 SCIPquadprecSumQD(delta, -oldcoeff, newcoeff);
758
759 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
760 {
761 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
762
763 if( SCIPisInfinity(scip, ub) )
764 return TRUE;
765 else
766 {
767 SCIPquadprecProdQD(delta, delta, ub);
768 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
769 }
770 }
771 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
772 {
773 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
774
775 if( SCIPisInfinity(scip, -lb) )
776 return TRUE;
777 else
778 {
779 SCIPquadprecProdQD(delta, delta, lb);
780 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
781 }
782 }
783
784 return FALSE;
785}
786
787/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
788 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse quad precision array;
789 *
790 * This is the quad precision version of cutTightenCoefs() below.
791 */
792static
794 SCIP* scip, /**< SCIP data structure */
795 SCIP_Bool cutislocal, /**< is the cut local? */
796 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
797 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
798 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
799 int* cutnnz, /**< the number of non-zeros in the cut */
800 SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
801 )
802{
803 int i;
804 int nintegralvars;
805 SCIP_Bool isintegral = TRUE;
806 SCIP_VAR** vars;
807 SCIP_Real QUAD(maxacttmp);
808 SCIP_Real maxact;
809 SCIP_Real maxabsintval = 0.0;
810 SCIP_Real maxabscontval = 0.0;
811
812 QUAD_ASSIGN(maxacttmp, 0.0);
813
814 vars = SCIPgetVars(scip);
815 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
816
817 assert(redundant != NULL);
818 *redundant = FALSE;
819
820 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
821 for( i = 0; i < *cutnnz; ++i )
822 {
823 SCIP_Real QUAD(val);
824
825 assert(cutinds[i] >= 0);
826 assert(vars[cutinds[i]] != NULL);
827
828 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
829
830 if( QUAD_TO_DBL(val) < 0.0 )
831 {
832 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
833
834 if( SCIPisInfinity(scip, -lb) )
835 return SCIP_OKAY;
836
837 if( cutinds[i] < nintegralvars )
838 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
839 else
840 {
841 maxabscontval = MAX(maxabscontval, -QUAD_TO_DBL(val));
842 isintegral = FALSE;
843 }
844
845 SCIPquadprecProdQD(val, val, lb);
846 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
847 }
848 else
849 {
850 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
851
852 if( SCIPisInfinity(scip, ub) )
853 return SCIP_OKAY;
854
855 if( cutinds[i] < nintegralvars )
856 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
857 else
858 {
859 maxabscontval = MAX(maxabscontval, QUAD_TO_DBL(val));
860 isintegral = FALSE;
861 }
862
863 SCIPquadprecProdQD(val, val, ub);
864 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
865 }
866 }
867
868 maxact = QUAD_TO_DBL(maxacttmp);
869
870 /* cut is redundant in activity bounds */
871 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
872 {
873 *redundant = TRUE;
874 return SCIP_OKAY;
875 }
876
877 /* cut is only on integral variables, try to scale to integral coefficients */
878 if( isintegral )
879 {
880 SCIP_Real equiscale;
881 SCIP_Real intscalar;
882 SCIP_Bool success;
883 SCIP_Real* intcoeffs;
884
885 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
886
887 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
888
889 for( i = 0; i < *cutnnz; ++i )
890 {
891 SCIP_Real QUAD(val);
892
893 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
894 SCIPquadprecProdQD(val, val, equiscale);
895
896 intcoeffs[i] = QUAD_TO_DBL(val);
897 }
898
900 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
901
902 SCIPfreeBufferArray(scip, &intcoeffs);
903
904 if( success )
905 {
906 /* if successful, apply the scaling */
907 intscalar *= equiscale;
908 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
909
910 for( i = 0; i < *cutnnz; )
911 {
912 SCIP_Real QUAD(val);
913 SCIP_Real intval;
914
915 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
916 SCIPquadprecProdQD(val, val, intscalar);
917
918 intval = SCIPround(scip, QUAD_TO_DBL(val));
919
920 if( chgQuadCoeffWithBound(scip, vars[cutinds[i]], QUAD(val), intval, cutislocal, QUAD(cutrhs)) )
921 {
922 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
923 *redundant = TRUE;
924 return SCIP_OKAY;
925 }
926
927 if( intval != 0.0 )
928 {
929 QUAD_ASSIGN(val, intval);
930 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
931 ++i;
932 }
933 else
934 {
935 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
936 QUAD_ASSIGN(val, 0.0);
937 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
938 --(*cutnnz);
939 cutinds[i] = cutinds[*cutnnz];
940 }
941 }
942
943 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
944
945 /* recompute the maximal activity after scaling to integral values */
946 QUAD_ASSIGN(maxacttmp, 0.0);
947 maxabsintval = 0.0;
948
949 for( i = 0; i < *cutnnz; ++i )
950 {
951 SCIP_Real QUAD(val);
952
953 assert(cutinds[i] >= 0);
954 assert(vars[cutinds[i]] != NULL);
955
956 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
957
958 if( QUAD_TO_DBL(val) < 0.0 )
959 {
960 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
961
962 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
963
964 SCIPquadprecProdQD(val, val, lb);
965
966 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
967 }
968 else
969 {
970 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
971
972 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
973
974 SCIPquadprecProdQD(val, val, ub);
975
976 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
977 }
978 }
979
980 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
981 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
982 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
983 }
984 else
985 {
986 /* otherwise, apply the equilibrium scaling */
987 isintegral = FALSE;
988
989 /* perform the scaling */
990 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
991 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
992 maxabsintval *= equiscale;
993
994 for( i = 0; i < *cutnnz; ++i )
995 {
996 SCIP_Real QUAD(val);
997
998 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
999 SCIPquadprecProdQD(val, val, equiscale);
1000 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1001 }
1002 }
1003 }
1004 else
1005 {
1006 /* cut has integer and continuous variables, so scale it to equilibrium */
1007 SCIP_Real scale;
1008 SCIP_Real maxabsval;
1009
1010 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
1011 maxabsval = MIN(maxabsval, maxabsintval);
1012 maxabsval = MAX(maxabsval, maxabscontval);
1013
1014 scale = 1.0 / maxabsval; /*lint !e795*/
1015
1016 /* perform the scaling */
1017 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
1018 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
1019 maxabsintval *= scale;
1020
1021 for( i = 0; i < *cutnnz; ++i )
1022 {
1023 SCIP_Real QUAD(val);
1024
1025 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1026 SCIPquadprecProdQD(val, val, scale);
1027 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
1028 }
1029 }
1030
1031 maxact = QUAD_TO_DBL(maxacttmp);
1032
1033 /* check again for redundancy after scaling */
1034 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1035 {
1036 *redundant = TRUE;
1037 return SCIP_OKAY;
1038 }
1039
1040 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1041 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
1042 return SCIP_OKAY;
1043
1044 SCIPsortDownInd(cutinds, compareAbsCoefsQuad, (void*) cutcoefs, *cutnnz);
1045
1046 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1047 for( i = 0; i < *cutnnz; )
1048 {
1049 SCIP_Real QUAD(val);
1050
1051 if( cutinds[i] >= nintegralvars )
1052 {
1053 ++i;
1054 continue;
1055 }
1056
1057 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1058
1059 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1060
1061 if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
1062 {
1063 SCIP_Real QUAD(coef);
1064 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1065
1066 SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
1067
1068 if( isintegral )
1069 {
1070 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1071 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1072 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1073 }
1074
1075 if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
1076 {
1077 SCIP_Real QUAD(delta);
1078 SCIP_Real QUAD(tmp);
1079
1080 SCIPquadprecSumQQ(delta, -val, coef);
1081 SCIPquadprecProdQD(delta, delta, lb);
1082
1083 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1084 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1085 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
1086 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1087
1088 QUAD_ASSIGN_Q(*cutrhs, tmp);
1089
1090 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
1091
1092 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
1093 {
1094 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1095 maxact = QUAD_TO_DBL(maxacttmp);
1096 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1097 }
1098 else
1099 {
1100 QUAD_ASSIGN(coef, 0.0);
1101 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1102 --(*cutnnz);
1103 cutinds[i] = cutinds[*cutnnz];
1104 continue;
1105 }
1106 }
1107 }
1108 else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
1109 {
1110 SCIP_Real QUAD(coef);
1111 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1112
1113 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
1114
1115 if( isintegral )
1116 {
1117 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1118 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1119 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1120 }
1121
1122 if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
1123 {
1124 SCIP_Real QUAD(delta);
1125 SCIP_Real QUAD(tmp);
1126
1127 SCIPquadprecSumQQ(delta, -val, coef);
1128 SCIPquadprecProdQD(delta, delta, ub);
1129
1130 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1131 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1132 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
1133 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1134
1135 QUAD_ASSIGN_Q(*cutrhs, tmp);
1136
1137 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
1138
1139 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
1140 {
1141 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1142 maxact = QUAD_TO_DBL(maxacttmp);
1143 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1144 }
1145 else
1146 {
1147 QUAD_ASSIGN(coef, 0.0);
1148 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1149 --(*cutnnz);
1150 cutinds[i] = cutinds[*cutnnz];
1151 continue;
1152 }
1153 }
1154 }
1155 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1156 break;
1157
1158 ++i;
1159 }
1160
1161 return SCIP_OKAY;
1162}
1163
1164/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
1165 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse array;
1166 */
1167static
1169 SCIP* scip, /**< SCIP data structure */
1170 SCIP_Bool cutislocal, /**< is the cut local? */
1171 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1172 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
1173 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1174 int* cutnnz, /**< the number of non-zeros in the cut */
1175 SCIP_Bool* redundant /**< pointer to return whtether the cut was detected to be redundant */
1176 )
1177{
1178 int i;
1179 int nintegralvars;
1180 SCIP_Bool isintegral = TRUE;
1181 SCIP_VAR** vars;
1182 SCIP_Real QUAD(maxacttmp);
1183 SCIP_Real maxact;
1184 SCIP_Real maxabsintval = 0.0;
1185 SCIP_Real maxabscontval = 0.0;
1186
1187 QUAD_ASSIGN(maxacttmp, 0.0);
1188
1189 vars = SCIPgetVars(scip);
1190 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1191
1192 assert(redundant != NULL);
1193 *redundant = FALSE;
1194
1195 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
1196 for( i = 0; i < *cutnnz; ++i )
1197 {
1198 SCIP_Real val;
1199 SCIP_Real QUAD(quadprod);
1200
1201 assert(cutinds[i] >= 0);
1202 assert(vars[cutinds[i]] != NULL);
1203
1204 val = cutcoefs[cutinds[i]];
1205
1206 if( val < 0.0 )
1207 {
1208 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1209
1210 if( SCIPisInfinity(scip, -lb) )
1211 return SCIP_OKAY;
1212
1213 if( cutinds[i] < nintegralvars )
1214 maxabsintval = MAX(maxabsintval, -val);
1215 else
1216 {
1217 maxabscontval = MAX(maxabscontval, -val);
1218 isintegral = FALSE;
1219 }
1220
1221 SCIPquadprecProdDD(quadprod, val, lb);
1222 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
1223 }
1224 else
1225 {
1226 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1227
1228 if( SCIPisInfinity(scip, ub) )
1229 return SCIP_OKAY;
1230
1231 if( cutinds[i] < nintegralvars )
1232 maxabsintval = MAX(maxabsintval, val);
1233 else
1234 {
1235 maxabscontval = MAX(maxabscontval, val);
1236 isintegral = FALSE;
1237 }
1238
1239 SCIPquadprecProdDD(quadprod, val, ub);
1240 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
1241 }
1242 }
1243
1244 maxact = QUAD_TO_DBL(maxacttmp);
1245
1246 /* cut is redundant in activity bounds */
1247 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1248 {
1249 *redundant = TRUE;
1250 return SCIP_OKAY;
1251 }
1252
1253 /* cut is only on integral variables, try to scale to integral coefficients */
1254 if( isintegral )
1255 {
1256 SCIP_Real equiscale;
1257 SCIP_Real intscalar;
1258 SCIP_Bool success;
1259 SCIP_Real* intcoeffs;
1260
1261 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
1262
1263 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
1264
1265 for( i = 0; i < *cutnnz; ++i )
1266 {
1267 SCIP_Real val;
1268
1269 val = equiscale * cutcoefs[cutinds[i]];
1270
1271 intcoeffs[i] = val;
1272 }
1273
1275 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
1276
1277 SCIPfreeBufferArray(scip, &intcoeffs);
1278
1279 if( success )
1280 {
1281 /* if successful, apply the scaling */
1282 intscalar *= equiscale;
1283 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
1284
1285 for( i = 0; i < *cutnnz; )
1286 {
1287 SCIP_Real val;
1288 SCIP_Real intval;
1289
1290 val = cutcoefs[cutinds[i]];
1291 val *= intscalar;
1292
1293 intval = SCIPround(scip, val);
1294
1295 if( chgCoeffWithBound(scip, vars[cutinds[i]], val, intval, cutislocal, QUAD(cutrhs)) )
1296 {
1297 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
1298 *redundant = TRUE;
1299 return SCIP_OKAY;
1300 }
1301
1302 if( intval != 0.0 )
1303 {
1304 cutcoefs[cutinds[i]] = intval;
1305 ++i;
1306 }
1307 else
1308 {
1309 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
1310 cutcoefs[cutinds[i]] = 0.0;
1311 --(*cutnnz);
1312 cutinds[i] = cutinds[*cutnnz];
1313 }
1314 }
1315
1316 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
1317
1318 /* recompute the maximal activity after scaling to integral values */
1319 QUAD_ASSIGN(maxacttmp, 0.0);
1320 maxabsintval = 0.0;
1321
1322 for( i = 0; i < *cutnnz; ++i )
1323 {
1324 SCIP_Real val;
1325 SCIP_Real QUAD(quadprod);
1326
1327 assert(cutinds[i] >= 0);
1328 assert(vars[cutinds[i]] != NULL);
1329
1330 val = cutcoefs[cutinds[i]];
1331
1332 if( val < 0.0 )
1333 {
1334 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1335
1336 maxabsintval = MAX(maxabsintval, -val);
1337
1338 SCIPquadprecProdDD(quadprod, val, lb);
1339 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
1340 }
1341 else
1342 {
1343 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1344
1345 maxabsintval = MAX(maxabsintval, val);
1346
1347 SCIPquadprecProdDD(quadprod, val, ub);
1348 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
1349 }
1350 }
1351
1352 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
1353 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
1354 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
1355 }
1356 else
1357 {
1358 /* otherwise, apply the equilibrium scaling */
1359 isintegral = FALSE;
1360
1361 /* perform the scaling */
1362 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
1363 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
1364 maxabsintval *= equiscale;
1365
1366 for( i = 0; i < *cutnnz; ++i )
1367 cutcoefs[cutinds[i]] *= equiscale;
1368 }
1369 }
1370 else
1371 {
1372 /* cut has integer and continuous variables, so scale it to equilibrium */
1373 SCIP_Real scale;
1374 SCIP_Real maxabsval;
1375
1376 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
1377 maxabsval = MIN(maxabsval, maxabsintval);
1378 maxabsval = MAX(maxabsval, maxabscontval);
1379
1380 scale = 1.0 / maxabsval; /*lint !e795*/
1381
1382 /* perform the scaling */
1383 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
1384 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
1385 maxabsintval *= scale;
1386
1387 for( i = 0; i < *cutnnz; ++i )
1388 cutcoefs[cutinds[i]] *= scale;
1389 }
1390
1391 maxact = QUAD_TO_DBL(maxacttmp);
1392
1393 /* check again for redundancy after scaling */
1394 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1395 {
1396 *redundant = TRUE;
1397 return SCIP_OKAY;
1398 }
1399
1400 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1401 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
1402 return SCIP_OKAY;
1403
1404 SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
1405
1406 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1407 for( i = 0; i < *cutnnz; )
1408 {
1409 SCIP_Real val;
1410
1411 if( cutinds[i] >= nintegralvars )
1412 {
1413 ++i;
1414 continue;
1415 }
1416
1417 val = cutcoefs[cutinds[i]];
1418
1419 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1420
1421 if( val < 0.0 && SCIPisLE(scip, maxact + val, QUAD_TO_DBL(*cutrhs)) )
1422 {
1423 SCIP_Real QUAD(coef);
1424 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1425
1426 SCIPquadprecSumQQ(coef, -maxacttmp, *cutrhs);
1427
1428 if( isintegral )
1429 {
1430 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1431 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1432 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1433 }
1434
1435 if( QUAD_TO_DBL(coef) > val )
1436 {
1437 SCIP_Real QUAD(delta);
1438 SCIP_Real QUAD(tmp);
1439
1440 SCIPquadprecSumQD(delta, coef, -val);
1441 SCIPquadprecProdQD(delta, delta, lb);
1442
1443 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1444 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1445 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
1446 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1447
1448 QUAD_ASSIGN_Q(*cutrhs, tmp);
1449
1450 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
1451
1452 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
1453 {
1454 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1455 maxact = QUAD_TO_DBL(maxacttmp);
1456 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
1457 }
1458 else
1459 {
1460 cutcoefs[cutinds[i]] = 0.0;
1461 --(*cutnnz);
1462 cutinds[i] = cutinds[*cutnnz];
1463 continue;
1464 }
1465 }
1466 }
1467 else if( val > 0.0 && SCIPisLE(scip, maxact - val, QUAD_TO_DBL(*cutrhs)) )
1468 {
1469 SCIP_Real QUAD(coef);
1470 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1471
1472 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
1473
1474 if( isintegral )
1475 {
1476 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1477 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1478 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1479 }
1480
1481 if( QUAD_TO_DBL(coef) < val )
1482 {
1483 SCIP_Real QUAD(delta);
1484 SCIP_Real QUAD(tmp);
1485
1486 SCIPquadprecSumQD(delta, coef, -val);
1487 SCIPquadprecProdQD(delta, delta, ub);
1488
1489 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1490 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1491 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
1492 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1493
1494 QUAD_ASSIGN_Q(*cutrhs, tmp);
1495
1496 assert(! SCIPisNegative(scip, QUAD_TO_DBL(coef)));
1497
1498 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
1499 {
1500 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1501 maxact = QUAD_TO_DBL(maxacttmp);
1502 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
1503 }
1504 else
1505 {
1506 cutcoefs[cutinds[i]] = 0.0;
1507 --(*cutnnz);
1508 cutinds[i] = cutinds[*cutnnz];
1509 continue;
1510 }
1511 }
1512 }
1513 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1514 break;
1515
1516 ++i;
1517 }
1518
1519 return SCIP_OKAY;
1520}
1521
1522/** perform activity based coefficient tightening on the given cut; returns TRUE if the cut was detected
1523 * to be redundant due to activity bounds
1524 *
1525 * See also cons_linear.c:consdataTightenCoefs().
1526 */
1528 SCIP* scip, /**< SCIP data structure */
1529 SCIP_Bool cutislocal, /**< is the cut local? */
1530 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1531 SCIP_Real* cutrhs, /**< the right hand side of the cut */
1532 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1533 int* cutnnz, /**< the number of non-zeros in the cut */
1534 int* nchgcoefs /**< number of changed coefficients */
1535 )
1536{
1537 int i;
1538 int nintegralvars;
1539 SCIP_VAR** vars;
1540 SCIP_Real* absvals;
1541 SCIP_Real QUAD(maxacttmp);
1542 SCIP_Real maxact;
1543 SCIP_Real maxabsval = 0.0;
1544 SCIP_Bool redundant = FALSE;
1545
1546 assert(nchgcoefs != NULL);
1547
1548 QUAD_ASSIGN(maxacttmp, 0.0);
1549
1550 vars = SCIPgetVars(scip);
1551 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1552 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &absvals, *cutnnz) );
1553
1554 assert(nchgcoefs != NULL);
1555 *nchgcoefs = 0;
1556
1557 for( i = 0; i < *cutnnz; ++i )
1558 {
1559 SCIP_Real QUAD(quadprod);
1560
1561 assert(cutinds[i] >= 0);
1562 assert(vars[cutinds[i]] != NULL);
1563
1564 if( cutcoefs[i] < 0.0 )
1565 {
1566 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1567
1568 if( SCIPisInfinity(scip, -lb) )
1569 goto TERMINATE;
1570
1571 if( cutinds[i] < nintegralvars )
1572 {
1573 maxabsval = MAX(maxabsval, -cutcoefs[i]);
1574 absvals[i] = -cutcoefs[i];
1575 }
1576 else
1577 absvals[i] = 0.0;
1578
1579 SCIPquadprecProdDD(quadprod, lb, cutcoefs[i]);
1580 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
1581 }
1582 else
1583 {
1584 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1585
1586 if( SCIPisInfinity(scip, ub) )
1587 goto TERMINATE;
1588
1589 if( cutinds[i] < nintegralvars )
1590 {
1591 maxabsval = MAX(maxabsval, cutcoefs[i]);
1592 absvals[i] = cutcoefs[i];
1593 }
1594 else
1595 absvals[i] = 0.0;
1596
1597 SCIPquadprecProdDD(quadprod, ub, cutcoefs[i]);
1598 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
1599 }
1600 }
1601
1602 maxact = QUAD_TO_DBL(maxacttmp);
1603
1604 /* cut is redundant in activity bounds */
1605 if( SCIPisFeasLE(scip, maxact, *cutrhs) )
1606 {
1607 redundant = TRUE;
1608 goto TERMINATE;
1609 }
1610
1611 /* terminate, because coefficient tightening cannot be performed; also excludes the case in which no integral variable is present */
1612 if( SCIPisGT(scip, maxact - maxabsval, *cutrhs) )
1613 goto TERMINATE;
1614
1615 SCIPsortDownRealRealInt(absvals, cutcoefs, cutinds, *cutnnz);
1616 SCIPfreeBufferArray(scip, &absvals);
1617
1618 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1619 for( i = 0; i < *cutnnz; ++i )
1620 {
1621 /* due to sorting, we can exit if we reached a continuous variable: all further integral variables have 0 coefficents anyway */
1622 if( cutinds[i] >= nintegralvars )
1623 break;
1624
1625 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1626
1627 if( cutcoefs[i] < 0.0 && SCIPisLE(scip, maxact + cutcoefs[i], *cutrhs) )
1628 {
1629 SCIP_Real coef = (*cutrhs) - maxact;
1630 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1631
1632 coef = SCIPfloor(scip, coef);
1633
1634 if( coef > cutcoefs[i] )
1635 {
1636 SCIP_Real QUAD(delta);
1637 SCIP_Real QUAD(tmp);
1638
1639 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
1640 SCIPquadprecProdQD(delta, delta, lb);
1641
1642 SCIPquadprecSumQD(tmp, delta, *cutrhs);
1643 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1644 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp), lb,
1645 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1646
1647 *cutrhs = QUAD_TO_DBL(tmp);
1648
1649 assert(!SCIPisPositive(scip, coef));
1650
1651 ++(*nchgcoefs);
1652
1653 if( SCIPisNegative(scip, coef) )
1654 {
1655 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1656 maxact = QUAD_TO_DBL(maxacttmp);
1657 cutcoefs[i] = coef;
1658 }
1659 else
1660 {
1661 --(*cutnnz);
1662 cutinds[i] = cutinds[*cutnnz];
1663 cutcoefs[i] = cutcoefs[*cutnnz];
1664 continue;
1665 }
1666 }
1667 }
1668 else if( cutcoefs[i] > 0.0 && SCIPisLE(scip, maxact - cutcoefs[i], *cutrhs) )
1669 {
1670 SCIP_Real coef = maxact - (*cutrhs);
1671 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1672
1673 coef = SCIPceil(scip, coef);
1674
1675 if( coef < cutcoefs[i] )
1676 {
1677 SCIP_Real QUAD(delta);
1678 SCIP_Real QUAD(tmp);
1679
1680 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
1681 SCIPquadprecProdQD(delta, delta, ub);
1682
1683 SCIPquadprecSumQD(tmp, delta, *cutrhs);
1684 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1685 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp),
1686 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1687
1688 *cutrhs = QUAD_TO_DBL(tmp);
1689
1690 assert(!SCIPisNegative(scip, coef));
1691
1692 ++(*nchgcoefs);
1693
1694 if( SCIPisPositive(scip, coef) )
1695 {
1696 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1697 maxact = QUAD_TO_DBL(maxacttmp);
1698 cutcoefs[i] = coef;
1699 }
1700 else
1701 {
1702 --(*cutnnz);
1703 cutinds[i] = cutinds[*cutnnz];
1704 cutcoefs[i] = cutcoefs[*cutnnz];
1705 continue;
1706 }
1707 }
1708 }
1709 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1710 break;
1711 }
1712
1713 TERMINATE:
1714 SCIPfreeBufferArrayNull(scip, &absvals);
1715
1716 return redundant;
1717}
1718
1719/* =========================================== aggregation row =========================================== */
1720
1721
1722/** create an empty aggregation row */
1724 SCIP* scip, /**< SCIP data structure */
1725 SCIP_AGGRROW** aggrrow /**< pointer to return aggregation row */
1726 )
1727{
1728 int nvars;
1729 assert(scip != NULL);
1730 assert(aggrrow != NULL);
1731
1732 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
1733
1734 nvars = SCIPgetNVars(scip);
1735
1736 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)) );
1737 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->inds, nvars) );
1738
1739 BMSclearMemoryArray((*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars));
1740
1741 (*aggrrow)->local = FALSE;
1742 (*aggrrow)->nnz = 0;
1743 (*aggrrow)->rank = 0;
1744 QUAD_ASSIGN((*aggrrow)->rhs, 0.0);
1745 (*aggrrow)->rowsinds = NULL;
1746 (*aggrrow)->slacksign = NULL;
1747 (*aggrrow)->rowweights = NULL;
1748 (*aggrrow)->nrows = 0;
1749 (*aggrrow)->rowssize = 0;
1750
1751 return SCIP_OKAY;
1752}
1753
1754/** free a aggregation row */
1756 SCIP* scip, /**< SCIP data structure */
1757 SCIP_AGGRROW** aggrrow /**< pointer to aggregation row that should be freed */
1758 )
1759{
1760 int nvars;
1761
1762 assert(scip != NULL);
1763 assert(aggrrow != NULL);
1764
1765 nvars = SCIPgetNVars(scip);
1766
1767 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->inds, nvars);
1768 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)); /*lint !e647*/
1769 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowsinds, (*aggrrow)->rowssize);
1770 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->slacksign, (*aggrrow)->rowssize);
1771 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowweights, (*aggrrow)->rowssize);
1772 SCIPfreeBlockMemory(scip, aggrrow);
1773}
1774
1775/** output aggregation row to file stream */
1777 SCIP* scip, /**< SCIP data structure */
1778 SCIP_AGGRROW* aggrrow, /**< pointer to return aggregation row */
1779 FILE* file /**< output file (or NULL for standard output) */
1780 )
1781{
1782 SCIP_VAR** vars;
1783 SCIP_MESSAGEHDLR* messagehdlr;
1784 int i;
1785
1786 assert(scip != NULL);
1787 assert(aggrrow != NULL);
1788
1789 vars = SCIPgetVars(scip);
1790 assert(vars != NULL);
1791
1792 messagehdlr = SCIPgetMessagehdlr(scip);
1793 assert(messagehdlr);
1794
1795 /* print coefficients */
1796 if( aggrrow->nnz == 0 )
1797 SCIPmessageFPrintInfo(messagehdlr, file, "0 ");
1798
1799 for( i = 0; i < aggrrow->nnz; ++i )
1800 {
1801 SCIP_Real QUAD(val);
1802
1803 QUAD_ARRAY_LOAD(val, aggrrow->vals, aggrrow->inds[i]);
1804 assert(SCIPvarGetProbindex(vars[aggrrow->inds[i]]) == aggrrow->inds[i]);
1805 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", QUAD_TO_DBL(val), SCIPvarGetName(vars[aggrrow->inds[i]]));
1806 }
1807
1808 /* print right hand side */
1809 SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", QUAD_TO_DBL(aggrrow->rhs));
1810}
1811
1812/** copy a aggregation row */
1814 SCIP* scip, /**< SCIP data structure */
1815 SCIP_AGGRROW** aggrrow, /**< pointer to return aggregation row */
1816 SCIP_AGGRROW* source /**< source aggregation row */
1817 )
1818{
1819 int nvars;
1820
1821 assert(scip != NULL);
1822 assert(aggrrow != NULL);
1823 assert(source != NULL);
1824
1825 nvars = SCIPgetNVars(scip);
1826 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
1827
1828 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->vals, source->vals, QUAD_ARRAY_SIZE(nvars)) );
1829 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->inds, source->inds, nvars) );
1830 (*aggrrow)->nnz = source->nnz;
1831 QUAD_ASSIGN_Q((*aggrrow)->rhs, source->rhs);
1832
1833 if( source->nrows > 0 )
1834 {
1835 assert(source->rowsinds != NULL);
1836 assert(source->slacksign != NULL);
1837 assert(source->rowweights != NULL);
1838
1839 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowsinds, source->rowsinds, source->nrows) );
1840 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->slacksign, source->slacksign, source->nrows) );
1841 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowweights, source->rowweights, source->nrows) );
1842 }
1843 else
1844 {
1845 (*aggrrow)->rowsinds = NULL;
1846 (*aggrrow)->slacksign = NULL;
1847 (*aggrrow)->rowweights = NULL;
1848 }
1849
1850 (*aggrrow)->nrows = source->nrows;
1851 (*aggrrow)->rowssize = source->nrows;
1852 (*aggrrow)->rank = source->rank;
1853 (*aggrrow)->local = source->local;
1854
1855 return SCIP_OKAY;
1856}
1857
1858/** add weighted row to aggregation row */
1860 SCIP* scip, /**< SCIP data structure */
1861 SCIP_AGGRROW* aggrrow, /**< aggregation row */
1862 SCIP_ROW* row, /**< row to add to aggregation row */
1863 SCIP_Real weight, /**< scale for adding given row to aggregation row */
1864 int sidetype /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
1865 )
1866{
1867 SCIP_Real QUAD(quadprod);
1868 SCIP_Real sideval;
1869 SCIP_Bool uselhs;
1870 int i;
1871
1872 assert(row->lppos >= 0);
1873
1874 /* update local flag */
1875 aggrrow->local = aggrrow->local || row->local;
1876
1877 /* update rank */
1878 aggrrow->rank = MAX(row->rank, aggrrow->rank);
1879
1880 i = aggrrow->nrows++;
1881
1882 if( aggrrow->nrows > aggrrow->rowssize )
1883 {
1884 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
1885 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
1886 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
1887 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
1888 aggrrow->rowssize = newsize;
1889 }
1890 aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
1891 aggrrow->rowweights[i] = weight;
1892
1893 if( sidetype == -1 )
1894 {
1895 assert( ! SCIPisInfinity(scip, -row->lhs) );
1896 uselhs = TRUE;
1897 }
1898 else if( sidetype == 1 )
1899 {
1900 assert( ! SCIPisInfinity(scip, row->rhs) );
1901 uselhs = FALSE;
1902 }
1903 else
1904 {
1905 /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
1906 * If possible, use the side that leads to a positive slack value in the summation.
1907 */
1908 if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
1909 uselhs = TRUE;
1910 else
1911 uselhs = FALSE;
1912 }
1913
1914 if( uselhs )
1915 {
1916 aggrrow->slacksign[i] = -1;
1917 sideval = row->lhs - row->constant;
1918 if( row->integral )
1919 sideval = SCIPceil(scip, sideval); /* row is integral: round left hand side up */
1920 }
1921 else
1922 {
1923 aggrrow->slacksign[i] = +1;
1924 sideval = row->rhs - row->constant;
1925 if( row->integral )
1926 sideval = SCIPfloor(scip, sideval); /* row is integral: round right hand side up */
1927 }
1928
1929 SCIPquadprecProdDD(quadprod, weight, sideval);
1930 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
1931
1932 /* add up coefficients */
1933 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
1934
1935 return SCIP_OKAY;
1936}
1937
1938/** Removes a given variable @p var from position @p pos the aggregation row and updates the right-hand side according
1939 * to sign of the coefficient, i.e., rhs -= coef * bound, where bound = lb if coef >= 0 and bound = ub, otherwise.
1940 *
1941 * @note: The choice of global or local bounds depend on the validity (global or local) of the aggregation row.
1942 *
1943 * @note: The list of non-zero indices will be updated by swapping the last non-zero index to @p pos.
1944 */
1946 SCIP* scip, /**< SCIP data structure */
1947 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
1948 SCIP_VAR* var, /**< variable that should be removed */
1949 int pos, /**< position of the variable in the aggregation row */
1950 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
1951 )
1952{
1953 SCIP_Real QUAD(val);
1954 int v;
1955
1956 assert(valid != NULL);
1957 assert(pos >= 0);
1958
1959 v = aggrrow->inds[pos];
1960 assert(v == SCIPvarGetProbindex(var));
1961
1962 QUAD_ARRAY_LOAD(val, aggrrow->vals, v);
1963
1964 *valid = TRUE;
1965
1966 /* adjust left and right hand sides with max contribution */
1967 if( QUAD_TO_DBL(val) < 0.0 )
1968 {
1969 SCIP_Real ub = aggrrow->local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
1970
1971 if( SCIPisInfinity(scip, ub) )
1972 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
1973 else
1974 {
1975 SCIPquadprecProdQD(val, val, ub);
1976 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
1977 }
1978 }
1979 else
1980 {
1981 SCIP_Real lb = aggrrow->local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
1982
1983 if( SCIPisInfinity(scip, -lb) )
1984 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
1985 else
1986 {
1987 SCIPquadprecProdQD(val, val, lb);
1988 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
1989 }
1990 }
1991
1992 QUAD_ASSIGN(val, 0.0);
1993 QUAD_ARRAY_STORE(aggrrow->vals, v, val);
1994
1995 /* remove non-zero entry */
1996 --(aggrrow->nnz);
1997 aggrrow->inds[pos] = aggrrow->inds[aggrrow->nnz];
1998
1999 if( SCIPisInfinity(scip, QUAD_HI(aggrrow->rhs)) )
2000 *valid = FALSE;
2001}
2002
2003/** add the objective function with right-hand side @p rhs and scaled by @p scale to the aggregation row */
2005 SCIP* scip, /**< SCIP data structure */
2006 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2007 SCIP_Real rhs, /**< right-hand side of the artificial row */
2008 SCIP_Real scale /**< scalar */
2009 )
2010{
2011 SCIP_VAR** vars;
2012 SCIP_Real QUAD(val);
2013 int nvars;
2014
2015 assert(scip != NULL);
2016 assert(aggrrow != NULL);
2017
2018 vars = SCIPgetVars(scip);
2019 nvars = SCIPgetNVars(scip);
2020
2021 /* add all variables straight forward if the aggregation row is empty */
2022 if( aggrrow->nnz == 0 )
2023 {
2024 int i;
2025 for( i = 0; i < nvars; ++i )
2026 {
2027 assert(SCIPvarGetProbindex(vars[i]) == i);
2028
2029 /* skip all variables with zero objective coefficient */
2030 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
2031 continue;
2032
2033 QUAD_ASSIGN(val, scale * SCIPvarGetObj(vars[i]));
2034 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
2035 aggrrow->inds[aggrrow->nnz++] = i;
2036 }
2037
2038 /* add right-hand side value */
2039 QUAD_ASSIGN(aggrrow->rhs, scale * rhs);
2040 }
2041 else
2042 {
2043 int i;
2044 SCIP_Real QUAD(quadprod);
2045 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
2046 for( i = 0 ; i < nvars; ++i )
2047 {
2048 SCIP_Real varobj;
2049 assert(SCIPvarGetProbindex(vars[i]) == i);
2050
2051 /* skip all variables with zero objective coefficient */
2052 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
2053 continue;
2054
2055 QUAD_ARRAY_LOAD(val, aggrrow->vals, i); /* val = aggrrow->vals[i] */
2056
2057 if( QUAD_HI(val) == 0.0 )
2058 aggrrow->inds[aggrrow->nnz++] = i;
2059
2060 varobj = SCIPvarGetObj(vars[i]);
2061 SCIPquadprecProdDD(quadprod, scale, varobj);
2062 SCIPquadprecSumQQ(val, val, quadprod);
2063
2064 /* the value must not be exactly zero due to sparsity pattern */
2065 QUAD_HI(val) = NONZERO(QUAD_HI(val));
2066 assert(QUAD_HI(val) != 0.0);
2067
2068 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
2069 }
2070
2071 /* add right-hand side value */
2072 SCIPquadprecProdDD(quadprod, scale, rhs);
2073 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
2074 }
2075
2076 return SCIP_OKAY;
2077}
2078
2079/** add weighted constraint to the aggregation row */
2081 SCIP* scip, /**< SCIP data structure */
2082 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2083 int* inds, /**< variable problem indices in constraint to add to the aggregation row */
2084 SCIP_Real* vals, /**< values of constraint to add to the aggregation row */
2085 int len, /**< length of constraint to add to the aggregation row */
2086 SCIP_Real rhs, /**< right hand side of constraint to add to the aggregation row */
2087 SCIP_Real weight, /**< (positive) scale for adding given constraint to the aggregation row */
2088 int rank, /**< rank to use for given constraint */
2089 SCIP_Bool local /**< is constraint only valid locally */
2090 )
2091{
2092 SCIP_Real QUAD(quadprod);
2093 int i;
2094
2095 assert(weight >= 0.0);
2096 assert(!SCIPisInfinity(scip, REALABS(weight * rhs)));
2097
2098 /* update local flag */
2099 aggrrow->local = aggrrow->local || local;
2100
2101 /* update rank */
2102 aggrrow->rank = MAX(rank, aggrrow->rank);
2103
2104 /* add right hand side value */
2105 SCIPquadprecProdDD(quadprod, weight, rhs);
2106 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
2107
2108 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
2109 for( i = 0 ; i < len; ++i )
2110 {
2111 SCIP_Real QUAD(val);
2112 int probindex = inds[i];
2113
2114 QUAD_ARRAY_LOAD(val, aggrrow->vals, probindex); /* val = aggrrow->vals[probindex] */
2115
2116 if( QUAD_HI(val) == 0.0 )
2117 aggrrow->inds[aggrrow->nnz++] = probindex;
2118
2119 SCIPquadprecProdDD(quadprod, vals[i], weight);
2120 SCIPquadprecSumQQ(val, val, quadprod);
2121
2122 /* the value must not be exactly zero due to sparsity pattern */
2123 QUAD_HI(val) = NONZERO(QUAD_HI(val));
2124 assert(QUAD_HI(val) != 0.0);
2125
2126 QUAD_ARRAY_STORE(aggrrow->vals, probindex, val);
2127 }
2128
2129 return SCIP_OKAY;
2130}
2131
2132/** clear all entries int the aggregation row but don't free memory */
2134 SCIP_AGGRROW* aggrrow /**< the aggregation row */
2135 )
2136{
2137 int i;
2138 SCIP_Real QUAD(tmp);
2139
2140 QUAD_ASSIGN(tmp, 0.0);
2141
2142 for( i = 0; i < aggrrow->nnz; ++i )
2143 {
2144 QUAD_ARRAY_STORE(aggrrow->vals, aggrrow->inds[i], tmp);
2145 }
2146
2147 aggrrow->nnz = 0;
2148 aggrrow->nrows = 0;
2149 aggrrow->rank = 0;
2150 QUAD_ASSIGN(aggrrow->rhs, 0.0);
2151 aggrrow->local = FALSE;
2152}
2153
2154/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
2155 *
2156 * @return the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
2157 */
2159 SCIP* scip, /**< SCIP data structure */
2160 SCIP_AGGRROW* aggrrow /**< the aggregation row */
2161 )
2162{
2163 return calcEfficacyNormQuad(scip, aggrrow->vals, aggrrow->inds, aggrrow->nnz);
2164}
2165
2166/** Adds one row to the aggregation row. Differs from SCIPaggrRowAddRow() by providing some additional
2167 * parameters required for SCIPaggrRowSumRows()
2168 */
2169static
2171 SCIP* scip, /**< SCIP data structure */
2172 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2173 SCIP_ROW* row, /**< the row to add */
2174 SCIP_Real weight, /**< weight of row to add */
2175 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
2176 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
2177 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
2178 int maxaggrlen, /**< maximal length of aggregation row */
2179 SCIP_Bool* rowtoolong /**< is the aggregated row too long */
2180 )
2181{
2182 SCIP_Real QUAD(quadprod);
2183 SCIP_Real sideval;
2184 SCIP_Bool uselhs;
2185 int i;
2186
2187 assert( rowtoolong != NULL );
2188 *rowtoolong = FALSE;
2189
2190 if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
2191 {
2192 return SCIP_OKAY;
2193 }
2194
2195 if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
2196 {
2198
2199 if( stat == SCIP_BASESTAT_LOWER )
2200 {
2201 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
2202 uselhs = TRUE;
2203 }
2204 else if( stat == SCIP_BASESTAT_UPPER )
2205 {
2206 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
2207 uselhs = FALSE;
2208 }
2209 else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
2210 uselhs = TRUE;
2211 else
2212 uselhs = FALSE;
2213 }
2214 else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
2215 uselhs = TRUE;
2216 else
2217 uselhs = FALSE;
2218
2219 if( uselhs )
2220 {
2221 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
2222
2223 if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
2224 return SCIP_OKAY;
2225
2226 sideval = row->lhs - row->constant;
2227 /* row is integral? round left hand side up */
2228 if( row->integral )
2229 sideval = SCIPceil(scip, sideval);
2230 }
2231 else
2232 {
2233 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
2234
2235 if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
2236 return SCIP_OKAY;
2237
2238 sideval = row->rhs - row->constant;
2239 /* row is integral? round right hand side down */
2240 if( row->integral )
2241 sideval = SCIPfloor(scip, sideval);
2242 }
2243
2244 /* add right hand side, update rank and local flag */
2245 SCIPquadprecProdDD(quadprod, sideval, weight);
2246 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
2247 aggrrow->rank = MAX(aggrrow->rank, row->rank);
2248 aggrrow->local = aggrrow->local || row->local;
2249
2250 /* ensure the array for storing the row information is large enough */
2251 i = aggrrow->nrows++;
2252 if( aggrrow->nrows > aggrrow->rowssize )
2253 {
2254 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
2255 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
2256 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
2257 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
2258 aggrrow->rowssize = newsize;
2259 }
2260
2261 /* add information of addditional row */
2262 aggrrow->rowsinds[i] = row->lppos;
2263 aggrrow->rowweights[i] = weight;
2264 aggrrow->slacksign[i] = uselhs ? -1 : 1;
2265
2266 /* add up coefficients */
2267 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
2268
2269 /* check if row is too long now */
2270 if( aggrrow->nnz > maxaggrlen )
2271 *rowtoolong = TRUE;
2272
2273 return SCIP_OKAY;
2274}
2275
2276/** aggregate rows using the given weights; the current content of the aggregation
2277 * row, \p aggrrow, gets overwritten
2278 */
2280 SCIP* scip, /**< SCIP data structure */
2281 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2282 SCIP_Real* weights, /**< row weights in row summation */
2283 int* rowinds, /**< array to store indices of non-zero entries of the weights array, or NULL */
2284 int nrowinds, /**< number of non-zero entries in weights array, -1 if rowinds is NULL */
2285 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
2286 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
2287 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
2288 int maxaggrlen, /**< maximal length of aggregation row */
2289 SCIP_Bool* valid /**< is the aggregation valid */
2290 )
2291{
2292 SCIP_ROW** rows;
2293 SCIP_VAR** vars;
2294 int nrows;
2295 int nvars;
2296 int k;
2297 SCIP_Bool rowtoolong;
2298
2299 assert( scip != NULL );
2300 assert( aggrrow != NULL );
2301 assert( valid != NULL );
2302
2303 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2304 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
2305
2306 SCIPaggrRowClear(aggrrow);
2307 *valid = FALSE;
2308
2309 if( rowinds != NULL && nrowinds > -1 )
2310 {
2311 for( k = 0; k < nrowinds; ++k )
2312 {
2313 SCIP_CALL( addOneRow(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
2314
2315 if( rowtoolong )
2316 return SCIP_OKAY;
2317 }
2318 }
2319 else
2320 {
2321 for( k = 0; k < nrows; ++k )
2322 {
2323 if( weights[k] != 0.0 )
2324 {
2325 SCIP_CALL( addOneRow(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
2326
2327 if( rowtoolong )
2328 return SCIP_OKAY;
2329 }
2330 }
2331 }
2332
2333 SCIPaggrRowRemoveZeros(scip, aggrrow, FALSE, valid);
2334
2335 return SCIP_OKAY;
2336}
2337
2338/** checks for cut redundancy and performs activity based coefficient tightening;
2339 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
2340 * to remove small coefficients (relative to the maximum absolute coefficient)
2341 */
2342static
2344 SCIP* scip, /**< SCIP data structure */
2345 SCIP_Bool cutislocal, /**< is the cut a local cut */
2346 int* cutinds, /**< variable problem indices of non-zeros in cut */
2347 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
2348 int* nnz, /**< number non-zeros coefficients of cut */
2349 SCIP_Real* cutrhs, /**< right hand side of cut */
2350 SCIP_Bool* success /**< pointer to return whether post-processing was succesful or cut is redundant */
2351 )
2352{
2353 int i;
2354 SCIP_Bool redundant;
2355 SCIP_Real maxcoef;
2356 SCIP_Real minallowedcoef;
2357 SCIP_Real QUAD(rhs);
2358
2359 assert(scip != NULL);
2360 assert(cutinds != NULL);
2361 assert(cutcoefs != NULL);
2362 assert(cutrhs != NULL);
2363 assert(success != NULL);
2364
2365 *success = FALSE;
2366
2367 QUAD_ASSIGN(rhs, *cutrhs);
2368
2369 if( removeZeros(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz) )
2370 {
2371 /* right hand side was changed to infinity -> cut is redundant */
2372 return SCIP_OKAY;
2373 }
2374
2375 if( *nnz == 0 )
2376 return SCIP_OKAY;
2377
2378 SCIP_CALL( cutTightenCoefs(scip, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz, &redundant) );
2379
2380 if( redundant )
2381 {
2382 /* cut is redundant */
2383 return SCIP_OKAY;
2384 }
2385
2386 maxcoef = 0.0;
2387 for( i = 0; i < *nnz; ++i )
2388 {
2389 SCIP_Real absval = REALABS(cutcoefs[cutinds[i]]);
2390 maxcoef = MAX(absval, maxcoef);
2391 }
2392
2393 maxcoef /= scip->set->sepa_maxcoefratio;
2394 minallowedcoef = SCIPsumepsilon(scip);
2395 minallowedcoef = MAX(minallowedcoef, maxcoef);
2396
2397 *success = ! removeZeros(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz);
2398 *cutrhs = QUAD_TO_DBL(rhs);
2399
2400 return SCIP_OKAY;
2401}
2402
2403
2404/** checks for cut redundancy and performs activity based coefficient tightening;
2405 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
2406 * to remove small coefficients (relative to the maximum absolute coefficient).
2407 * The cutcoefs must be a quad precision array, i.e. allocated with size
2408 * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
2409 * macros.
2410 */
2411static
2413 SCIP* scip, /**< SCIP data structure */
2414 SCIP_Bool cutislocal, /**< is the cut a local cut */
2415 int* cutinds, /**< variable problem indices of non-zeros in cut */
2416 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
2417 int* nnz, /**< number non-zeros coefficients of cut */
2418 QUAD(SCIP_Real* cutrhs), /**< right hand side of cut */
2419 SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
2420 )
2421{
2422 int i;
2423 SCIP_Bool redundant;
2424 SCIP_Real maxcoef;
2425 SCIP_Real minallowedcoef;
2426
2427 assert(scip != NULL);
2428 assert(cutinds != NULL);
2429 assert(cutcoefs != NULL);
2430 assert(QUAD_HI(cutrhs) != NULL);
2431 assert(success != NULL);
2432
2433 *success = FALSE;
2434
2435 if( removeZerosQuad(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz) )
2436 {
2437 /* right hand side was changed to infinity -> cut is redundant */
2438 return SCIP_OKAY;
2439 }
2440
2441 if( *nnz == 0 )
2442 return SCIP_OKAY;
2443
2444 SCIP_CALL( cutTightenCoefsQuad(scip, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz, &redundant) );
2445 if( redundant )
2446 {
2447 /* cut is redundant */
2448 return SCIP_OKAY;
2449 }
2450
2451 maxcoef = 0.0;
2452 for( i = 0; i < *nnz; ++i )
2453 {
2454 SCIP_Real abscoef;
2455 SCIP_Real QUAD(coef);
2456 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]); /* coef = cutcoefs[cutinds[i]] */
2457 abscoef = REALABS(QUAD_TO_DBL(coef));
2458 maxcoef = MAX(abscoef, maxcoef);
2459 }
2460
2461 maxcoef /= scip->set->sepa_maxcoefratio;
2462 minallowedcoef = SCIPsumepsilon(scip);
2463 minallowedcoef = MAX(minallowedcoef, maxcoef);
2464
2465 *success = ! removeZerosQuad(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz);
2466
2467 return SCIP_OKAY;
2468}
2469
2470/** removes almost zero entries from the aggregation row. */
2472 SCIP* scip, /**< SCIP datastructure */
2473 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2474 SCIP_Bool useglbbounds, /**< consider global bound although the cut is local? */
2475 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
2476 )
2477{
2478 assert(aggrrow != NULL);
2479 assert(valid != NULL);
2480
2481 *valid = ! removeZerosQuad(scip, SCIPsumepsilon(scip), useglbbounds ? FALSE : aggrrow->local, aggrrow->vals,
2482 QUAD(&aggrrow->rhs), aggrrow->inds, &aggrrow->nnz);
2483}
2484
2485/** get number of aggregated rows */
2487 SCIP_AGGRROW* aggrrow /**< the aggregation row */
2488 )
2489{
2490 assert(aggrrow != NULL);
2491
2492 return aggrrow->nrows;
2493}
2494
2495/** get array with lp positions of rows used in aggregation */
2497 SCIP_AGGRROW* aggrrow /**< the aggregation row */
2498 )
2499{
2500 assert(aggrrow != NULL);
2501 assert(aggrrow->rowsinds != NULL || aggrrow->nrows == 0);
2502
2503 return aggrrow->rowsinds;
2504}
2505
2506/** get array with weights of aggregated rows */
2508 SCIP_AGGRROW* aggrrow /**< the aggregation row */
2509 )
2510{
2511 assert(aggrrow != NULL);
2512 assert(aggrrow->rowweights != NULL || aggrrow->nrows == 0);
2513
2514 return aggrrow->rowweights;
2515}
2516
2517/** checks whether a given row has been added to the aggregation row */
2519 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2520 SCIP_ROW* row /**< row for which it is checked whether it has been added to the aggregation */
2521 )
2522{
2523 int i;
2524 int rowind;
2525
2526 assert(aggrrow != NULL);
2527 assert(row != NULL);
2528
2529 rowind = SCIProwGetLPPos(row);
2530
2531 for( i = 0; i < aggrrow->nrows; ++i )
2532 {
2533 if( aggrrow->rowsinds[i] == rowind )
2534 return TRUE;
2535 }
2536
2537 return FALSE;
2538}
2539
2540/** gets the array of corresponding variable problem indices for each non-zero in the aggregation row */
2542 SCIP_AGGRROW* aggrrow /**< aggregation row */
2543 )
2544{
2545 assert(aggrrow != NULL);
2546
2547 return aggrrow->inds;
2548}
2549
2550/** gets the number of non-zeros in the aggregation row */
2552 SCIP_AGGRROW* aggrrow /**< aggregation row */
2553 )
2554{
2555 assert(aggrrow != NULL);
2556
2557 return aggrrow->nnz;
2558}
2559
2560/** gets the rank of the aggregation row */
2562 SCIP_AGGRROW* aggrrow /**< aggregation row */
2563 )
2564{
2565 assert(aggrrow != NULL);
2566
2567 return aggrrow->rank;
2568}
2569
2570/** checks if the aggregation row is only valid locally */
2572 SCIP_AGGRROW* aggrrow /**< aggregation row */
2573 )
2574{
2575 assert(aggrrow != NULL);
2576
2577 return aggrrow->local;
2578}
2579
2580/** gets the right hand side of the aggregation row */
2582 SCIP_AGGRROW* aggrrow /**< aggregation row */
2583 )
2584{
2585 assert(aggrrow != NULL);
2586
2587 return QUAD_TO_DBL(aggrrow->rhs);
2588}
2589
2590/* =========================================== c-MIR =========================================== */
2591
2592#define MAXCMIRSCALE 1e+6 /**< maximal scaling (scale/(1-f0)) allowed in c-MIR calculations */
2593
2594/** finds the best lower bound of the variable to use for MIR transformation */
2595static
2597 SCIP* scip, /**< SCIP data structure */
2598 SCIP_VAR* var, /**< problem variable */
2599 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2600 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
2601 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2602 SCIP_Real* bestlb, /**< pointer to store best bound value */
2603 SCIP_Real* simplebound, /**< pointer to store simple bound value */
2604 int* bestlbtype /**< pointer to store best bound type */
2605 )
2606{
2607 assert(bestlb != NULL);
2608 assert(bestlbtype != NULL);
2609
2610 *bestlb = SCIPvarGetLbGlobal(var);
2611 *bestlbtype = -1;
2612
2613 if( allowlocal )
2614 {
2615 SCIP_Real loclb;
2616
2617 loclb = SCIPvarGetLbLocal(var);
2618 if( SCIPisGT(scip, loclb, *bestlb) )
2619 {
2620 *bestlb = loclb;
2621 *bestlbtype = -2;
2622 }
2623 }
2624
2625 *simplebound = *bestlb;
2626
2627 if( usevbds && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
2628 {
2629 SCIP_Real bestvlb;
2630 int bestvlbidx;
2631
2632 SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
2633 if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
2634 {
2635 SCIP_VAR** vlbvars;
2636
2637 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
2638 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
2639 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
2640 */
2641 vlbvars = SCIPvarGetVlbVars(var);
2642 assert(vlbvars != NULL);
2643 if( (usevbds == 2 || SCIPvarGetType(vlbvars[bestvlbidx]) == SCIP_VARTYPE_BINARY) &&
2644 SCIPvarGetProbindex(vlbvars[bestvlbidx]) < SCIPvarGetProbindex(var) )
2645 {
2646 *bestlb = bestvlb;
2647 *bestlbtype = bestvlbidx;
2648 }
2649 }
2650 }
2651
2652 return SCIP_OKAY;
2653}
2654
2655/** finds the best upper bound of the variable to use for MIR transformation */
2656static
2658 SCIP* scip, /**< SCIP data structure */
2659 SCIP_VAR* var, /**< problem variable */
2660 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2661 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
2662 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2663 SCIP_Real* bestub, /**< pointer to store best bound value */
2664 SCIP_Real* simplebound, /**< pointer to store simple bound */
2665 int* bestubtype /**< pointer to store best bound type */
2666 )
2667{
2668 assert(bestub != NULL);
2669 assert(bestubtype != NULL);
2670
2671 *bestub = SCIPvarGetUbGlobal(var);
2672 *bestubtype = -1;
2673
2674 if( allowlocal )
2675 {
2676 SCIP_Real locub;
2677
2678 locub = SCIPvarGetUbLocal(var);
2679 if( SCIPisLT(scip, locub, *bestub) )
2680 {
2681 *bestub = locub;
2682 *bestubtype = -2;
2683 }
2684 }
2685
2686 *simplebound = *bestub;
2687
2688 if( usevbds && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
2689 {
2690 SCIP_Real bestvub;
2691 int bestvubidx;
2692
2693 SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
2694 if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
2695 {
2696 SCIP_VAR** vubvars;
2697
2698 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
2699 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
2700 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
2701 */
2702 vubvars = SCIPvarGetVubVars(var);
2703 assert(vubvars != NULL);
2704 if( (usevbds == 2 || SCIPvarGetType(vubvars[bestvubidx]) == SCIP_VARTYPE_BINARY) &&
2705 SCIPvarGetProbindex(vubvars[bestvubidx]) < SCIPvarGetProbindex(var) )
2706 {
2707 *bestub = bestvub;
2708 *bestubtype = bestvubidx;
2709 }
2710 }
2711 }
2712
2713 return SCIP_OKAY;
2714}
2715
2716/** determine the best bounds with respect to the given solution for complementing the given variable */
2717static
2719 SCIP* scip, /**< SCIP data structure */
2720 SCIP_VAR* var, /**< variable to determine best bound for */
2721 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2722 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
2723 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
2724 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2725 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
2726 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
2727 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
2728 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
2729 * NULL for using closest bound for all variables */
2730 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
2731 * NULL for using closest bound for all variables */
2732 SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
2733 SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
2734 int* bestlbtype, /**< pointer to store type of best lower bound of variable */
2735 int* bestubtype, /**< pointer to store type of best upper bound of variable */
2736 SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
2737 SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
2738 )
2739{
2740 SCIP_Real simplelb;
2741 SCIP_Real simpleub;
2742 int v;
2743
2744 v = SCIPvarGetProbindex(var);
2745
2746 /* check if the user specified a bound to be used */
2747 if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
2748 {
2749 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || ( boundsfortrans[v] == -2 || boundsfortrans[v] == -1 ));
2750 assert(boundtypesfortrans != NULL);
2751
2752 /* user has explicitly specified a bound to be used */
2753 if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
2754 {
2755 /* user wants to use lower bound */
2756 *bestlbtype = boundsfortrans[v];
2757 if( *bestlbtype == -1 )
2758 *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
2759 else if( *bestlbtype == -2 )
2760 *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
2761 else
2762 {
2763 SCIP_VAR** vlbvars;
2764 SCIP_Real* vlbcoefs;
2765 SCIP_Real* vlbconsts;
2766 int k;
2767
2768 assert(!ignoresol);
2769
2770 /* use the given variable lower bound */
2771 vlbvars = SCIPvarGetVlbVars(var);
2772 vlbcoefs = SCIPvarGetVlbCoefs(var);
2773 vlbconsts = SCIPvarGetVlbConstants(var);
2774 k = boundsfortrans[v];
2775 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
2776 assert(vlbvars != NULL);
2777 assert(vlbcoefs != NULL);
2778 assert(vlbconsts != NULL);
2779
2780 *bestlb = vlbcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[k]) : SCIPgetSolVal(scip, sol, vlbvars[k])) + vlbconsts[k];
2781 }
2782
2783 assert(!SCIPisInfinity(scip, - *bestlb));
2784 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2785
2786 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
2787 SCIP_CALL( findBestUb(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
2788 }
2789 else
2790 {
2791 assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
2792
2793 /* user wants to use upper bound */
2794 *bestubtype = boundsfortrans[v];
2795 if( *bestubtype == -1 )
2796 *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
2797 else if( *bestubtype == -2 )
2798 *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
2799 else
2800 {
2801 SCIP_VAR** vubvars;
2802 SCIP_Real* vubcoefs;
2803 SCIP_Real* vubconsts;
2804 int k;
2805
2806 assert(!ignoresol);
2807
2808 /* use the given variable upper bound */
2809 vubvars = SCIPvarGetVubVars(var);
2810 vubcoefs = SCIPvarGetVubCoefs(var);
2811 vubconsts = SCIPvarGetVubConstants(var);
2812 k = boundsfortrans[v];
2813 assert(k >= 0 && k < SCIPvarGetNVubs(var));
2814 assert(vubvars != NULL);
2815 assert(vubcoefs != NULL);
2816 assert(vubconsts != NULL);
2817
2818 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
2819 *bestub = vubcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vubvars[k]) : SCIPgetSolVal(scip, sol, vubvars[k])) + vubconsts[k];
2820 }
2821
2822 assert(!SCIPisInfinity(scip, *bestub));
2823 *selectedbound = SCIP_BOUNDTYPE_UPPER;
2824
2825 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
2826 SCIP_CALL( findBestLb(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
2827 }
2828 }
2829 else
2830 {
2831 SCIP_Real varsol;
2832
2833 /* bound selection should be done automatically */
2834
2835 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
2836 SCIP_CALL( findBestLb(scip, var, sol, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
2837
2838 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
2839 SCIP_CALL( findBestUb(scip, var, sol, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
2840
2841 /* check, if variable is free variable */
2842 if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
2843 {
2844 /* we found a free variable in the row with non-zero coefficient
2845 * -> MIR row can't be transformed in standard form
2846 */
2847 *freevariable = TRUE;
2848 return SCIP_OKAY;
2849 }
2850
2851 if( !ignoresol )
2852 {
2853 /* select transformation bound */
2854 varsol = (sol == NULL ? SCIPvarGetLPSol(var) : SCIPgetSolVal(scip, sol, var));
2855
2856 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
2857 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2858 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
2859 *selectedbound = SCIP_BOUNDTYPE_UPPER;
2860 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
2861 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2862 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
2863 *selectedbound = SCIP_BOUNDTYPE_UPPER;
2864 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
2865 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2866 else if( *bestubtype == -1 ) /* prefer global standard bounds */
2867 *selectedbound = SCIP_BOUNDTYPE_UPPER;
2868 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
2869 {
2870 if( *bestlb - simplelb > simpleub - *bestub )
2871 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2872 else
2873 *selectedbound = SCIP_BOUNDTYPE_UPPER;
2874 }
2875 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
2876 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2877 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
2878 *selectedbound = SCIP_BOUNDTYPE_UPPER;
2879 else /* no decision yet? just use lower bound */
2880 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2881 }
2882 else
2883 {
2884 SCIP_Real glbub = SCIPvarGetUbGlobal(var);
2885 SCIP_Real glblb = SCIPvarGetLbGlobal(var);
2886 SCIP_Real distlb = REALABS(glblb - *bestlb);
2887 SCIP_Real distub = REALABS(glbub - *bestub);
2888
2889 assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
2890
2891 if( SCIPisInfinity(scip, - *bestlb) )
2892 *selectedbound = SCIP_BOUNDTYPE_UPPER;
2893 else if( !SCIPisNegative(scip, *bestlb) )
2894 {
2895 if( SCIPisInfinity(scip, *bestub) )
2896 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2897 else if( SCIPisZero(scip, glblb) )
2898 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2899 else if( SCIPisLE(scip, distlb, distub) )
2900 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2901 else
2902 *selectedbound = SCIP_BOUNDTYPE_UPPER;
2903 }
2904 else
2905 {
2906 assert(!SCIPisInfinity(scip, - *bestlb));
2907 *selectedbound = SCIP_BOUNDTYPE_LOWER;
2908 }
2909 }
2910 }
2911
2912 return SCIP_OKAY; /*lint !e438*/
2913}
2914
2915/** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index */
2916static
2918 SCIP* scip, /**< SCIP datastructure */
2919 int* cutinds, /**< index array of nonzeros in the cut */
2920 SCIP_Real* cutcoefs, /**< array of cut coefficients */
2921 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
2922 int* nnz, /**< pointer to number of nonzeros of the cut */
2923 int varsign, /**< stores the sign of the transformed variable in summation */
2924 int boundtype, /**< stores the bound used for transformed variable:
2925 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
2926 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
2927 int probindex, /**< problem index of variable to perform the substitution step for */
2928 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
2929 )
2930{
2931 SCIP_Real QUAD(coef);
2932 SCIP_Real QUAD(tmp);
2933
2934 assert(!SCIPisInfinity(scip, -varsign * boundval));
2935
2936 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
2937
2938 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
2939 if( boundtype < 0 )
2940 {
2941 SCIPquadprecProdQD(tmp, coef, boundval);
2942 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
2943 *localbdsused = *localbdsused || (boundtype == -2);
2944 }
2945 else
2946 {
2947 SCIP_VAR** vbdvars;
2948 SCIP_Real* vbdcoefs;
2949 SCIP_Real* vbdconsts;
2950 SCIP_Real QUAD(zcoef);
2951 int zidx;
2952 SCIP_VAR* var = SCIPgetVars(scip)[probindex];
2953
2954 if( varsign == +1 )
2955 {
2956 vbdvars = SCIPvarGetVlbVars(var);
2957 vbdcoefs = SCIPvarGetVlbCoefs(var);
2958 vbdconsts = SCIPvarGetVlbConstants(var);
2959 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
2960 }
2961 else
2962 {
2963 vbdvars = SCIPvarGetVubVars(var);
2964 vbdcoefs = SCIPvarGetVubCoefs(var);
2965 vbdconsts = SCIPvarGetVubConstants(var);
2966 assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
2967 }
2968
2969 assert(vbdvars != NULL);
2970 assert(vbdcoefs != NULL);
2971 assert(vbdconsts != NULL);
2972 assert(SCIPvarIsActive(vbdvars[boundtype]));
2973
2974 zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
2975
2976 SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
2977 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
2978
2979 /* check if integral variable already exists in the row */
2980 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
2981
2982 if( QUAD_HI(zcoef) == 0.0 )
2983 cutinds[(*nnz)++] = zidx;
2984
2985 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
2986 SCIPquadprecSumQQ(zcoef, zcoef, tmp);
2987
2988 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
2989 assert(QUAD_HI(zcoef) != 0.0);
2990
2991 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
2992 }
2993}
2994
2995/** performs the bound substitution step with the simple bound for the variable with the given problem index */
2996static
2998 SCIP* scip, /**< SCIP datastructure */
2999 SCIP_Real* cutcoefs, /**< array of cut coefficients */
3000 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
3001 int boundtype, /**< stores the bound used for transformed variable:
3002 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
3003 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
3004 int probindex, /**< problem index of variable to perform the substitution step for */
3005 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
3006 )
3007{
3008 SCIP_Real QUAD(coef);
3009 SCIP_Real QUAD(tmp);
3010
3011 assert(!SCIPisInfinity(scip, ABS(boundval)));
3012
3013 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
3014
3015 /* must be a standard bound */
3016 assert( boundtype < 0 );
3017
3018 SCIPquadprecProdQD(tmp, coef, boundval);
3019 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
3020 *localbdsused = *localbdsused || (boundtype == -2);
3021}
3022
3023
3024/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
3025 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
3026 *
3027 * Transform variables (lb or ub):
3028 * \f[
3029 * \begin{array}{llll}
3030 * 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},\\
3031 * 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},
3032 * \end{array}
3033 * \f]
3034 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
3035 *
3036 * Transform variables (vlb or vub):
3037 * \f[
3038 * \begin{array}{llll}
3039 * 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.} \\
3040 * 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.}
3041 * \end{array}
3042 * \f]
3043 * 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:
3044 * \f[
3045 * \begin{array}{ll}
3046 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
3047 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
3048 * \end{array}
3049 * \f]
3050 */
3051static
3053 SCIP* scip, /**< SCIP data structure */
3054 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
3055 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
3056 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
3057 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
3058 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
3059 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
3060 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
3061 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
3062 * NULL for using closest bound for all variables */
3063 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
3064 * NULL for using closest bound for all variables */
3065 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
3066 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
3067 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
3068 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
3069 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
3070 int* nnz, /**< number of non-zeros in cut */
3071 int* varsign, /**< stores the sign of the transformed variable in summation */
3072 int* boundtype, /**< stores the bound used for transformed variable:
3073 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
3074 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
3075 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
3076 )
3077{
3078 SCIP_Real QUAD(tmp);
3079 SCIP_Real* bestlbs;
3080 SCIP_Real* bestubs;
3081 int* bestlbtypes;
3082 int* bestubtypes;
3083 SCIP_BOUNDTYPE* selectedbounds;
3084 int i;
3085 int aggrrowintstart;
3086 int nvars;
3087 int firstcontvar;
3088 SCIP_VAR** vars;
3089
3090 assert(varsign != NULL);
3091 assert(boundtype != NULL);
3092 assert(freevariable != NULL);
3093 assert(localbdsused != NULL);
3094
3095 *freevariable = FALSE;
3096 *localbdsused = FALSE;
3097
3098 /* allocate temporary memory to store best bounds and bound types */
3099 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*(*nnz)) );
3100 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*(*nnz)) );
3101 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*(*nnz)) );
3102 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*(*nnz)) );
3103 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*(*nnz)) );
3104
3105 /* start with continuous variables, because using variable bounds can affect the untransformed integral
3106 * variables, and these changes have to be incorporated in the transformation of the integral variables
3107 * (continuous variables have largest problem indices!)
3108 */
3109 SCIPsortDownInt(cutinds, *nnz);
3110
3111 vars = SCIPgetVars(scip);
3112 nvars = SCIPgetNVars(scip);
3113 firstcontvar = nvars - SCIPgetNContVars(scip);
3114
3115 /* determine the best bounds for the continuous variables */
3116 for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
3117 {
3118 SCIP_CALL( determineBestBounds(scip, vars[cutinds[i]], sol, boundswitch, usevbds ? 2 : 0, allowlocal, fixintegralrhs,
3119 ignoresol, boundsfortrans, boundtypesfortrans,
3120 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
3121
3122 if( *freevariable )
3123 goto TERMINATE;
3124 }
3125
3126 /* remember start of integer variables in the aggrrow */
3127 aggrrowintstart = i;
3128
3129 /* perform bound substitution for continuous variables */
3130 for( i = 0; i < aggrrowintstart; ++i )
3131 {
3132 int v = cutinds[i];
3133
3134 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
3135 {
3136 assert(!SCIPisInfinity(scip, -bestlbs[i]));
3137
3138 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
3139 boundtype[i] = bestlbtypes[i];
3140 varsign[i] = +1;
3141
3142 performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestlbs[i], v, localbdsused);
3143 }
3144 else
3145 {
3146 assert(!SCIPisInfinity(scip, bestubs[i]));
3147
3148 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
3149 boundtype[i] = bestubtypes[i];
3150 varsign[i] = -1;
3151
3152 performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestubs[i], v, localbdsused);
3153 }
3154 }
3155
3156 /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
3157 * and determine the bound to use for the integer variables that are left
3158 */
3159 while( i < *nnz )
3160 {
3161 SCIP_Real QUAD(coef);
3162 int v = cutinds[i];
3163 assert(cutinds[i] < firstcontvar);
3164
3165 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
3166
3167 /* due to variable bound usage for the continuous variables cancellation may have occurred */
3168 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
3169 {
3170 QUAD_ASSIGN(coef, 0.0);
3171 QUAD_ARRAY_STORE(cutcoefs, v, coef);
3172 --(*nnz);
3173 cutinds[i] = cutinds[*nnz];
3174 /* do not increase i, since last element is copied to the i-th position */
3175 continue;
3176 }
3177
3178 /* determine the best bounds for the integral variable, usevbd can be set to 0 here as vbds are only used for continuous variables */
3179 SCIP_CALL( determineBestBounds(scip, vars[v], sol, boundswitch, 0, allowlocal, fixintegralrhs,
3180 ignoresol, boundsfortrans, boundtypesfortrans,
3181 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
3182
3183 /* increase i */
3184 ++i;
3185
3186 if( *freevariable )
3187 goto TERMINATE;
3188 }
3189
3190 /* now perform the bound substitution on the remaining integral variables which only uses standard bounds */
3191 for( i = aggrrowintstart; i < *nnz; ++i )
3192 {
3193 int v = cutinds[i];
3194
3195 /* perform bound substitution */
3196 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
3197 {
3198 assert(!SCIPisInfinity(scip, - bestlbs[i]));
3199 assert(bestlbtypes[i] < 0);
3200
3201 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
3202 boundtype[i] = bestlbtypes[i];
3203 varsign[i] = +1;
3204
3205 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlbs[i], v, localbdsused);
3206 }
3207 else
3208 {
3209 assert(!SCIPisInfinity(scip, bestubs[i]));
3210 assert(bestubtypes[i] < 0);
3211
3212 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
3213 boundtype[i] = bestubtypes[i];
3214 varsign[i] = -1;
3215
3216 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestubs[i], v, localbdsused);
3217 }
3218 }
3219
3220 if( fixintegralrhs )
3221 {
3222 SCIP_Real f0;
3223
3224 /* check if rhs is fractional */
3225 f0 = EPSFRAC(QUAD_TO_DBL(*cutrhs), SCIPsumepsilon(scip));
3226 if( f0 < minfrac || f0 > maxfrac )
3227 {
3228 SCIP_Real bestviolgain;
3229 SCIP_Real bestnewf0;
3230 int besti;
3231
3232 /* choose complementation of one variable differently such that f0 is in correct range */
3233 besti = -1;
3234 bestviolgain = -1e+100;
3235 bestnewf0 = 1.0;
3236 for( i = 0; i < *nnz; i++ )
3237 {
3238 int v;
3239 SCIP_Real QUAD(coef);
3240
3241 v = cutinds[i];
3242 assert(0 <= v && v < nvars);
3243
3244 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
3245 assert(!EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON));
3246
3247 if( boundtype[i] < 0
3248 && ((varsign[i] == +1 && !SCIPisInfinity(scip, bestubs[i]) && bestubtypes[i] < 0)
3249 || (varsign[i] == -1 && !SCIPisInfinity(scip, -bestlbs[i]) && bestlbtypes[i] < 0)) )
3250 {
3251 SCIP_Real fj;
3252 SCIP_Real newfj;
3253 SCIP_Real newrhs;
3254 SCIP_Real newf0;
3255 SCIP_Real solval;
3256 SCIP_Real viol;
3257 SCIP_Real newviol;
3258 SCIP_Real violgain;
3259
3260 /* currently: a'_j = varsign * a_j -> f'_j = a'_j - floor(a'_j)
3261 * after complementation: a''_j = -varsign * a_j -> f''_j = a''_j - floor(a''_j) = 1 - f'_j
3262 * rhs'' = rhs' + varsign * a_j * (lb_j - ub_j)
3263 * cut violation from f0 and fj: f'_0 - f'_j * x'_j
3264 * after complementation: f''_0 - f''_j * x''_j
3265 *
3266 * for continuous variables, we just set f'_j = f''_j = |a'_j|
3267 */
3268 newrhs = QUAD_TO_DBL(*cutrhs) + varsign[i] * QUAD_TO_DBL(coef) * (bestlbs[i] - bestubs[i]);
3269 newf0 = EPSFRAC(newrhs, SCIPsumepsilon(scip));
3270
3271 if( newf0 < minfrac || newf0 > maxfrac )
3272 continue;
3273 if( v >= firstcontvar )
3274 {
3275 fj = REALABS(QUAD_TO_DBL(coef));
3276 newfj = fj;
3277 }
3278 else
3279 {
3280 fj = SCIPfrac(scip, varsign[i] * QUAD_TO_DBL(coef));
3281 newfj = SCIPfrac(scip, -varsign[i] * QUAD_TO_DBL(coef));
3282 }
3283
3284 if( !ignoresol )
3285 {
3286 solval = (sol == NULL ? SCIPvarGetLPSol(vars[v]) : SCIPgetSolVal(scip, sol, vars[v]));
3287 viol = f0 - fj * (varsign[i] == +1 ? solval - bestlbs[i] : bestubs[i] - solval);
3288 newviol = newf0 - newfj * (varsign[i] == -1 ? solval - bestlbs[i] : bestubs[i] - solval);
3289 violgain = newviol - viol;
3290 }
3291 else
3292 {
3293 /* todo: this should be done, this can improve the dualray significantly */
3294 SCIPerrorMessage("Cannot handle closest bounds with ignoring the LP solution.\n");
3295 return SCIP_INVALIDCALL;
3296 }
3297
3298 /* prefer larger violations; for equal violations, prefer smaller f0 values since then the possibility that
3299 * we f_j > f_0 is larger and we may improve some coefficients in rounding
3300 */
3301 if( SCIPisGT(scip, violgain, bestviolgain) || (SCIPisGE(scip, violgain, bestviolgain) && newf0 < bestnewf0) )
3302 {
3303 besti = i;
3304 bestviolgain = violgain;
3305 bestnewf0 = newf0;
3306 }
3307 }
3308 }
3309
3310 if( besti >= 0 )
3311 {
3312 SCIP_Real QUAD(coef);
3313 assert(besti < *nnz);
3314 assert(boundtype[besti] < 0);
3315 assert(!SCIPisInfinity(scip, -bestlbs[besti]));
3316 assert(!SCIPisInfinity(scip, bestubs[besti]));
3317
3318 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[besti]);
3319 QUAD_SCALE(coef, varsign[besti]);
3320
3321 /* switch the complementation of this variable */
3322 SCIPquadprecSumDD(tmp, bestlbs[besti], - bestubs[besti]);
3323 SCIPquadprecProdQQ(tmp, tmp, coef);
3324 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3325
3326 if( varsign[besti] == +1 )
3327 {
3328 /* switch to upper bound */
3329 assert(bestubtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
3330 boundtype[besti] = bestubtypes[besti];
3331 varsign[besti] = -1;
3332 }
3333 else
3334 {
3335 /* switch to lower bound */
3336 assert(bestlbtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
3337 boundtype[besti] = bestlbtypes[besti];
3338 varsign[besti] = +1;
3339 }
3340 *localbdsused = *localbdsused || (boundtype[besti] == -2);
3341 }
3342 }
3343 }
3344
3345 TERMINATE:
3346
3347 /*free temporary memory */
3348 SCIPfreeBufferArray(scip, &selectedbounds);
3349 SCIPfreeBufferArray(scip, &bestubtypes);
3350 SCIPfreeBufferArray(scip, &bestlbtypes);
3351 SCIPfreeBufferArray(scip, &bestubs);
3352 SCIPfreeBufferArray(scip, &bestlbs);
3353
3354 return SCIP_OKAY;
3355}
3356
3357/** 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$
3358 * \f[
3359 * \begin{array}{rll}
3360 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
3361 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
3362 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
3363 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
3364 * \end{array}
3365 * \f]
3366 *
3367 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
3368 *
3369 * (lb or ub):
3370 * \f[
3371 * \begin{array}{lllll}
3372 * 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}, \\
3373 * 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},
3374 * \end{array}
3375 * \f]
3376 * and move the constant terms
3377 * \f[
3378 * \begin{array}{cl}
3379 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
3380 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
3381 * \end{array}
3382 * \f]
3383 * to the rhs.
3384 *
3385 * (vlb or vub):
3386 * \f[
3387 * \begin{array}{lllll}
3388 * 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)} \\
3389 * 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)}
3390 * \end{array}
3391 * \f]
3392 * move the constant terms
3393 * \f[
3394 * \begin{array}{cl}
3395 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
3396 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
3397 * \end{array}
3398 * \f]
3399 * to the rhs, and update the VB variable coefficients:
3400 * \f[
3401 * \begin{array}{ll}
3402 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
3403 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
3404 * \end{array}
3405 * \f]
3406 */
3407static
3409 SCIP* scip, /**< SCIP data structure */
3410 SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
3411 QUAD(SCIP_Real*RESTRICT cutrhs), /**< pointer to right hand side of cut */
3412 int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
3413 int*RESTRICT nnz, /**< number of non-zeros in cut */
3414 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
3415 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
3416 QUAD(SCIP_Real f0) /**< fractional value of rhs */
3417 )
3418{
3419 SCIP_Real QUAD(tmp);
3420 SCIP_Real QUAD(onedivoneminusf0);
3421 int i;
3422 int firstcontvar;
3423 SCIP_VAR** vars;
3424 int ndelcontvars;
3425
3426 assert(QUAD_HI(cutrhs) != NULL);
3427 assert(cutcoefs != NULL);
3428 assert(cutinds != NULL);
3429 assert(nnz != NULL);
3430 assert(boundtype != NULL);
3431 assert(varsign != NULL);
3432 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
3433
3434 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
3435 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
3436
3437 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
3438 * without destroying the ordering of the aggrrow's non-zeros.
3439 * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
3440 */
3441
3442 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
3443 vars = SCIPgetVars(scip);
3444#ifndef NDEBUG
3445 /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
3446 i = 0;
3447 while( i < *nnz && cutinds[i] >= firstcontvar )
3448 ++i;
3449
3450 while( i < *nnz )
3451 {
3452 assert(cutinds[i] < firstcontvar);
3453 ++i;
3454 }
3455#endif
3456
3457 /* consider integral variables */
3458 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
3459 {
3460 SCIP_VAR* var;
3461 SCIP_Real QUAD(cutaj);
3462 int v;
3463
3464 v = cutinds[i];
3465 assert(0 <= v && v < SCIPgetNVars(scip));
3466
3467 var = vars[v];
3468 assert(var != NULL);
3469 assert(SCIPvarGetProbindex(var) == v);
3470 assert(varsign[i] == +1 || varsign[i] == -1);
3471
3472 /* calculate the coefficient in the retransformed cut */
3473 {
3474 SCIP_Real QUAD(aj);
3475 SCIP_Real QUAD(downaj);
3476 SCIP_Real QUAD(fj);
3477
3478 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
3479 QUAD_SCALE(aj, varsign[i]);
3480
3481 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
3482 SCIPquadprecSumQQ(fj, aj, -downaj);
3483 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
3484
3485 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
3486 {
3487 QUAD_ASSIGN_Q(cutaj, downaj); /* a^_j */
3488 }
3489 else
3490 {
3491 SCIPquadprecSumQQ(tmp, fj, -f0);
3492 SCIPquadprecProdQQ(tmp, tmp, onedivoneminusf0);
3493 SCIPquadprecSumQQ(cutaj, tmp, downaj);
3494 }
3495 QUAD_SCALE(cutaj, varsign[i]);
3496 }
3497
3498 /* remove zero cut coefficients from cut */
3499 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
3500 {
3501 QUAD_ASSIGN(cutaj, 0.0);
3502 QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3503 --*nnz;
3504 cutinds[i] = cutinds[*nnz];
3505 continue;
3506 }
3507
3508 QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3509
3510 /* integral var uses standard bound */
3511 assert(boundtype[i] < 0);
3512
3513 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
3514 if( varsign[i] == +1 )
3515 {
3516 /* lower bound was used */
3517 if( boundtype[i] == -1 )
3518 {
3519 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
3520 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
3521 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetLbGlobal(var) */
3522 }
3523 else
3524 {
3525 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
3526 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
3527 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetLbLocal(var) */
3528 }
3529 }
3530 else
3531 {
3532 /* upper bound was used */
3533 if( boundtype[i] == -1 )
3534 {
3535 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
3536 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
3537 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetUbGlobal(var) */
3538 }
3539 else
3540 {
3541 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
3542 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
3543 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetUbLocal(var) */
3544 }
3545 }
3546 }
3547
3548 /* now process the continuous variables; postpone deletion of zeros untill all continuous variables have been processed */
3549 ndelcontvars = 0;
3550 while( i >= ndelcontvars )
3551 {
3552 SCIP_VAR* var;
3553 SCIP_Real QUAD(cutaj);
3554 SCIP_Real QUAD(aj);
3555 int v;
3556
3557 v = cutinds[i];
3558 assert(0 <= v && v < SCIPgetNVars(scip));
3559
3560 var = vars[v];
3561 assert(var != NULL);
3562 assert(SCIPvarGetProbindex(var) == v);
3563 assert(varsign[i] == +1 || varsign[i] == -1);
3564 assert( v >= firstcontvar );
3565
3566 /* calculate the coefficient in the retransformed cut */
3567 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
3568
3569 if( QUAD_TO_DBL(aj) * varsign[i] >= 0.0 )
3570 QUAD_ASSIGN(cutaj, 0.0);
3571 else
3572 SCIPquadprecProdQQ(cutaj, onedivoneminusf0, aj); /* cutaj = aj * onedivoneminusf0 */
3573
3574 /* remove zero cut coefficients from cut; move a continuous var from the beginning
3575 * to the current position, so that all integral variables stay behind the continuous
3576 * variables
3577 */
3578 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
3579 {
3580 QUAD_ASSIGN(cutaj, 0.0);
3581 QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3582 cutinds[i] = cutinds[ndelcontvars];
3583 varsign[i] = varsign[ndelcontvars];
3584 boundtype[i] = boundtype[ndelcontvars];
3585 ++ndelcontvars;
3586 continue;
3587 }
3588
3589 QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3590
3591 /* check for variable bound use */
3592 if( boundtype[i] < 0 )
3593 {
3594 /* standard bound */
3595
3596 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
3597 if( varsign[i] == +1 )
3598 {
3599 /* lower bound was used */
3600 if( boundtype[i] == -1 )
3601 {
3602 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
3603 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
3604 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3605 }
3606 else
3607 {
3608 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
3609 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
3610 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3611 }
3612 }
3613 else
3614 {
3615 /* upper bound was used */
3616 if( boundtype[i] == -1 )
3617 {
3618 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
3619 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
3620 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3621 }
3622 else
3623 {
3624 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
3625 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
3626 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3627 }
3628 }
3629 }
3630 else
3631 {
3632 SCIP_VAR** vbz;
3633 SCIP_Real* vbb;
3634 SCIP_Real* vbd;
3635 SCIP_Real QUAD(zcoef);
3636 int vbidx;
3637 int zidx;
3638
3639 /* variable bound */
3640 vbidx = boundtype[i];
3641
3642 /* change mirrhs and cutaj of integer variable z_j of variable bound */
3643 if( varsign[i] == +1 )
3644 {
3645 /* variable lower bound was used */
3646 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
3647 vbz = SCIPvarGetVlbVars(var);
3648 vbb = SCIPvarGetVlbCoefs(var);
3649 vbd = SCIPvarGetVlbConstants(var);
3650 }
3651 else
3652 {
3653 /* variable upper bound was used */
3654 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
3655 vbz = SCIPvarGetVubVars(var);
3656 vbb = SCIPvarGetVubCoefs(var);
3657 vbd = SCIPvarGetVubConstants(var);
3658 }
3659 assert(SCIPvarIsActive(vbz[vbidx]));
3660 zidx = SCIPvarGetProbindex(vbz[vbidx]);
3661 assert(0 <= zidx && zidx < firstcontvar);
3662
3663 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
3664 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3665
3666 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
3667 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
3668
3669 /* update sparsity pattern */
3670 if( QUAD_HI(zcoef) == 0.0 )
3671 cutinds[(*nnz)++] = zidx;
3672
3673 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
3674 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
3675 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
3676 assert(QUAD_HI(zcoef) != 0.0);
3677 }
3678
3679 /* advance to next variable */
3680 --i;
3681 }
3682
3683 /* fill the empty position due to deleted continuous variables */
3684 if( ndelcontvars > 0 )
3685 {
3686 assert(ndelcontvars <= *nnz);
3687 *nnz -= ndelcontvars;
3688 if( *nnz < ndelcontvars )
3689 {
3690 BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
3691 }
3692 else
3693 {
3694 BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
3695 }
3696 }
3697
3698 return SCIP_OKAY;
3699}
3700
3701/** substitute aggregated slack variables:
3702 *
3703 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
3704 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r]. \f$
3705 *
3706 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
3707 * \f[
3708 * \begin{array}{rll}
3709 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r \leq f_0 \\
3710 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f_0)/(1 - f_0),& \mbox{if}\qquad f_r > f_0 \\
3711 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r \geq 0 \\
3712 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f_0), & \mbox{if}\qquad a^\prime_r < 0
3713 * \end{array}
3714 * \f]
3715 *
3716 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
3717 */
3718static
3720 SCIP* scip, /**< SCIP data structure */
3721 SCIP_Real* weights, /**< row weights in row summation */
3722 int* slacksign, /**< stores the sign of the row's slack variable in summation */
3723 int* rowinds, /**< sparsity pattern of used rows */
3724 int nrowinds, /**< number of used rows */
3725 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
3726 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
3727 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
3728 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
3729 int* nnz, /**< number of non-zeros in cut */
3730 QUAD(SCIP_Real f0) /**< fractional value of rhs */
3731 )
3732{ /*lint --e{715}*/
3733 SCIP_ROW** rows;
3734 SCIP_Real QUAD(onedivoneminusf0);
3735 int i;
3736
3737 assert(scip != NULL);
3738 assert(weights != NULL || nrowinds == 0);
3739 assert(slacksign != NULL || nrowinds == 0);
3740 assert(rowinds != NULL || nrowinds == 0);
3741 assert(scale > 0.0);
3742 assert(cutcoefs != NULL);
3743 assert(QUAD_HI(cutrhs) != NULL);
3744 assert(cutinds != NULL);
3745 assert(nnz != NULL);
3746 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
3747
3748 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
3749 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
3750
3751 rows = SCIPgetLPRows(scip);
3752 for( i = 0; i < nrowinds; i++ )
3753 {
3754 SCIP_ROW* row;
3755 SCIP_Real QUAD(ar);
3756 SCIP_Real QUAD(downar);
3757 SCIP_Real QUAD(cutar);
3758 SCIP_Real QUAD(fr);
3759 SCIP_Real QUAD(tmp);
3760 SCIP_Real QUAD(myprod);
3761 int r;
3762
3763 r = rowinds[i]; /*lint !e613*/
3764 assert(0 <= r && r < SCIPgetNLPRows(scip));
3765 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
3766 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
3767
3768 row = rows[r];
3769 assert(row != NULL);
3770 assert(row->len == 0 || row->cols != NULL);
3771 assert(row->len == 0 || row->cols_index != NULL);
3772 assert(row->len == 0 || row->vals != NULL);
3773
3774 /* get the slack's coefficient a'_r in the aggregated row */
3775 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
3776
3777 /* calculate slack variable's coefficient a^_r in the cut */
3778 if( row->integral )
3779 {
3780 /* slack variable is always integral:
3781 * a^_r = a~_r = down(a'_r) , if f_r <= f0
3782 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
3783 */
3784 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
3785 SCIPquadprecSumQQ(fr, ar, -downar);
3786 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
3787
3788 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
3789 QUAD_ASSIGN_Q(cutar, downar); /* a^_r */
3790 else
3791 {
3792 SCIPquadprecSumQQ(cutar, fr, -f0);
3793 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
3794 SCIPquadprecSumQQ(cutar, cutar, downar);
3795 }
3796 }
3797 else
3798 {
3799 /* slack variable is continuous:
3800 * a^_r = a~_r = 0 , if a'_r >= 0
3801 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
3802 */
3803 if( QUAD_TO_DBL(ar) >= 0.0 )
3804 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
3805 else
3806 SCIPquadprecProdQQ(cutar, onedivoneminusf0, ar);
3807 }
3808
3809 /* if the coefficient was reduced to zero, ignore the slack variable */
3810 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
3811 continue;
3812
3813 /* depending on the slack's sign, we have
3814 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
3815 * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
3816 */
3817 SCIPquadprecProdQD(myprod, cutar, -slacksign[i]);
3818
3819 /* add the slack's definition multiplied with a^_j to the cut */
3820 SCIP_CALL( varVecAddScaledRowCoefsQuadScale(cutinds, cutcoefs, nnz, row, QUAD(myprod)) );
3821
3822 /* move slack's constant to the right hand side */
3823 if( slacksign[i] == +1 ) /*lint !e613*/
3824 {
3825 SCIP_Real QUAD(rowrhs);
3826
3827 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
3828 assert(!SCIPisInfinity(scip, row->rhs));
3829 QUAD_ASSIGN(rowrhs, row->rhs - row->constant);
3830 if( row->integral )
3831 {
3832 /* the right hand side was implicitly rounded down in row aggregation */
3833 SCIPquadprecEpsFloorQ(rowrhs, rowrhs, SCIPepsilon(scip)); /*lint !e666*/
3834 }
3835 SCIPquadprecProdQQ(tmp, myprod, rowrhs);
3836 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3837 }
3838 else
3839 {
3840 SCIP_Real QUAD(rowlhs);
3841
3842 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
3843 assert(!SCIPisInfinity(scip, -row->lhs));
3844 QUAD_ASSIGN(rowlhs, row->lhs - row->constant);
3845 if( row->integral )
3846 {
3847 /* the left hand side was implicitly rounded up in row aggregation */
3848 SCIPquadprecEpsCeilQ(rowlhs, rowlhs, SCIPepsilon(scip)); /*lint !e666*/
3849 }
3850 SCIPquadprecProdQQ(tmp, myprod, rowlhs);
3851 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3852 }
3853 }
3854
3855 /* relax rhs to zero, if it's very close to 0 */
3856 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
3857 QUAD_ASSIGN(*cutrhs, 0.0);
3858
3859 return SCIP_OKAY;
3860}
3861
3862/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
3863 * these rows cannot participate in an MIR cut.
3864 *
3865 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
3866 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
3867 *
3868 * @pre This method can be called if @p scip is in one of the following stages:
3869 * - \ref SCIP_STAGE_SOLVING
3870 *
3871 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
3872 */
3874 SCIP* scip, /**< SCIP data structure */
3875 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
3876 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
3877 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
3878 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
3879 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
3880 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
3881 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
3882 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
3883 * NULL for using closest bound for all variables */
3884 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
3885 * NULL for using closest bound for all variables */
3886 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
3887 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
3888 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
3889 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
3890 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
3891 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
3892 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
3893 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
3894 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
3895 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
3896 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
3897 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
3898 )
3899{
3900 int i;
3901 int nvars;
3902 int tmpnnz;
3903 int* varsign;
3904 int* boundtype;
3905 int* tmpinds;
3906 SCIP_Real* tmpcoefs;
3907
3908 SCIP_Real QUAD(rhs);
3909 SCIP_Real QUAD(downrhs);
3910 SCIP_Real QUAD(f0);
3911 SCIP_Bool freevariable;
3912 SCIP_Bool localbdsused;
3913 SCIP_Bool tmpislocal;
3914
3915 assert(aggrrow != NULL);
3916 assert(SCIPisPositive(scip, scale));
3917 assert(success != NULL);
3918
3919 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
3920
3921 *success = FALSE;
3922
3923 /* allocate temporary memory */
3924 nvars = SCIPgetNVars(scip);
3925 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
3926 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
3927 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
3929
3930 /* initialize cut with aggregation */
3931 tmpnnz = aggrrow->nnz;
3932 tmpislocal = aggrrow->local;
3933
3934 SCIPquadprecProdQD(rhs, aggrrow->rhs, scale);
3935
3936 if( tmpnnz > 0 )
3937 {
3938 BMScopyMemoryArray(tmpinds, aggrrow->inds, tmpnnz);
3939
3940 for( i = 0; i < tmpnnz; ++i )
3941 {
3942 SCIP_Real QUAD(coef);
3943 int k = aggrrow->inds[i];
3944
3945 QUAD_ARRAY_LOAD(coef, aggrrow->vals, k);
3946
3947 SCIPquadprecProdQD(coef, coef, scale);
3948
3949 QUAD_ARRAY_STORE(tmpcoefs, k, coef);
3950
3951 assert(QUAD_HI(coef) != 0.0);
3952 }
3953
3954 /* Transform equation a*x == b, lb <= x <= ub into standard form
3955 * a'*x' == b, 0 <= x' <= ub'.
3956 *
3957 * Transform variables (lb or ub):
3958 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
3959 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
3960 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
3961 *
3962 * Transform variables (vlb or vub):
3963 * 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.
3964 * 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.
3965 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
3966 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
3967 * a_{zu_j} := a_{zu_j} + a_j * bu_j
3968 */
3969 SCIP_CALL( cutsTransformMIR(scip, sol, boundswitch, usevbds, allowlocal, fixintegralrhs, FALSE,
3970 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, varsign, boundtype, &freevariable, &localbdsused) );
3971 assert(allowlocal || !localbdsused);
3972 tmpislocal = tmpislocal || localbdsused;
3973
3974 if( freevariable )
3975 goto TERMINATE;
3976
3977 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
3978 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE));
3979 }
3980
3981 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
3982 * a~*x' <= down(b)
3983 * integers : a~_j = down(a'_j) , if f_j <= f_0
3984 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
3985 * continuous: a~_j = 0 , if a'_j >= 0
3986 * a~_j = a'_j/(1 - f0) , if a'_j < 0
3987 *
3988 * Transform inequality back to a^*x <= rhs:
3989 *
3990 * (lb or ub):
3991 * 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
3992 * 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
3993 * and move the constant terms
3994 * -a~_j * lb_j == -a^_j * lb_j, or
3995 * a~_j * ub_j == -a^_j * ub_j
3996 * to the rhs.
3997 *
3998 * (vlb or vub):
3999 * 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)
4000 * 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)
4001 * move the constant terms
4002 * -a~_j * dl_j == -a^_j * dl_j, or
4003 * a~_j * du_j == -a^_j * du_j
4004 * to the rhs, and update the VB variable coefficients:
4005 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
4006 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
4007 */
4008 SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
4009 SCIPquadprecSumQQ(f0, rhs, -downrhs);
4010 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
4011
4012 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
4013 goto TERMINATE;
4014
4015 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
4016 * If this gives a scalar that is very big, we better do not generate this cut.
4017 */
4018 if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
4019 goto TERMINATE;
4020
4021 /* renormalize f0 value */
4022 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
4023
4024 QUAD_ASSIGN_Q(rhs, downrhs);
4025
4026 if( tmpnnz > 0 )
4027 {
4028 SCIP_CALL( cutsRoundMIR(scip, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, varsign, boundtype, QUAD(f0)) );
4029
4030 SCIPdebugMsg(scip, "After MIR rounding:\n");
4031 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE));
4032 }
4033
4034 /* substitute aggregated slack variables:
4035 *
4036 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
4037 * variable only appears in its own row:
4038 * a'_r = scale * weight[r] * slacksign[r].
4039 *
4040 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
4041 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
4042 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
4043 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
4044 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
4045 *
4046 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
4047 */
4048 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
4049 aggrrow->nrows, scale, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, QUAD(f0)) );
4050
4051 SCIPdebugMsg(scip, "After slack substitution:\n");
4052 SCIPdebug( printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE) );
4053
4054 if( postprocess )
4055 {
4056 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
4057 * prevent numerical rounding errors
4058 */
4059 SCIP_CALL( postprocessCutQuad(scip, tmpislocal, tmpinds, tmpcoefs, &tmpnnz, QUAD(&rhs), success) );
4060 }
4061 else
4062 {
4063 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), tmpislocal, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz);
4064 }
4065
4066 SCIPdebugMsg(scip, "After post processing:\n");
4067 SCIPdebug( printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE) );
4068
4069 if( *success )
4070 {
4071 SCIP_Real mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, tmpcoefs, QUAD_TO_DBL(rhs), tmpinds, tmpnnz);
4072
4073 if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
4074 {
4075 BMScopyMemoryArray(cutinds, tmpinds, tmpnnz);
4076 *cutnnz = tmpnnz;
4077 *cutrhs = QUAD_TO_DBL(rhs);
4078 *cutislocal = tmpislocal;
4079
4080 /* clean tmpcoefs and go back to double precision */
4081 for( i = 0; i < *cutnnz; ++i )
4082 {
4083 SCIP_Real QUAD(coef);
4084 int j = cutinds[i];
4085
4086 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
4087
4088 cutcoefs[i] = QUAD_TO_DBL(coef);
4089 QUAD_ASSIGN(coef, 0.0);
4090 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
4091 }
4092
4093 if( cutefficacy != NULL )
4094 *cutefficacy = mirefficacy;
4095
4096 if( cutrank != NULL )
4097 *cutrank = aggrrow->rank + 1;
4098 }
4099 else
4100 {
4101 *success = FALSE;
4102 }
4103 }
4104
4105 TERMINATE:
4106 if( !(*success) )
4107 {
4108 SCIP_Real QUAD(tmp);
4109
4110 QUAD_ASSIGN(tmp, 0.0);
4111 for( i = 0; i < tmpnnz; ++i )
4112 {
4113 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[i], tmp);
4114 }
4115 }
4116
4117 /* free temporary memory */
4118 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
4119 SCIPfreeBufferArray(scip, &tmpinds);
4120 SCIPfreeBufferArray(scip, &boundtype);
4121 SCIPfreeBufferArray(scip, &varsign);
4122
4123 return SCIP_OKAY;
4124}
4125
4126/** compute the efficacy of the MIR cut for the given values without computing the cut.
4127 * This is used for the CMIR cut generation heuristic.
4128 */
4129static
4131 SCIP* scip, /**< SCIP datastructure */
4132 SCIP_Real*RESTRICT coefs, /**< array with coefficients in row */
4133 SCIP_Real*RESTRICT solvals, /**< solution values of variables in the row */
4134 SCIP_Real rhs, /**< right hand side of MIR cut */
4135 SCIP_Real contactivity, /**< aggregated activity of continuous variables in the row */
4136 SCIP_Real contsqrnorm, /**< squared norm of continuous variables */
4137 SCIP_Real delta, /**< delta value to compute the violation for */
4138 int nvars, /**< number of variables in the row, i.e. the size of coefs and solvals arrays */
4139 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4140 SCIP_Real maxfrac /**< maximal fractionality of rhs to produce MIR cut for */
4141 )
4142{
4143 int i;
4144 SCIP_Real f0pluseps;
4145 SCIP_Real f0;
4146 SCIP_Real onedivoneminusf0;
4147 SCIP_Real scale;
4148 SCIP_Real downrhs;
4149 SCIP_Real norm;
4150 SCIP_Real contscale;
4151
4152 scale = 1.0 / delta;
4153 rhs *= scale;
4154 downrhs = SCIPfloor(scip, rhs);
4155 f0 = rhs - downrhs;
4156
4157 if( f0 < minfrac || f0 > maxfrac )
4158 return 0.0;
4159
4160 onedivoneminusf0 = 1.0 / (1.0 - f0);
4161
4162 contscale = scale * onedivoneminusf0;
4163
4164 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
4165 * If this gives a scalar that is very big, we better do not generate this cut.
4166 */
4167 if( contscale > MAXCMIRSCALE )
4168 return 0.0;
4169
4170 rhs = downrhs;
4171 rhs -= contscale * contactivity;
4172 norm = SQR(contscale) * contsqrnorm;
4173
4174 assert(!SCIPisFeasZero(scip, f0));
4175 assert(!SCIPisFeasZero(scip, 1.0 - f0));
4176
4177 f0pluseps = f0 + SCIPepsilon(scip);
4178
4179 for( i = 0; i < nvars; ++i )
4180 {
4181 SCIP_Real floorai = SCIPfloor(scip, scale * coefs[i]);
4182 SCIP_Real fi = (scale * coefs[i]) - floorai;
4183
4184 if( fi > f0pluseps )
4185 floorai += (fi - f0) * onedivoneminusf0;
4186
4187 rhs -= solvals[i] * floorai;
4188 norm += SQR(floorai);
4189 }
4190
4191 norm = sqrt(norm);
4192
4193 return - rhs / MAX(norm, 1e-6);
4194}
4195
4196/** calculates an MIR cut out of an aggregation of LP rows
4197 *
4198 * Given the aggregation, it is transformed to a mixed knapsack set via complementation (using bounds or variable bounds)
4199 * Then, different scalings of the mkset are used to generate a MIR and the best is chosen.
4200 * One of the steps of the MIR is to round the coefficients of the integer variables down,
4201 * so one would prefer to have integer coefficients for integer variables which are far away from their bounds in the
4202 * mkset.
4203 *
4204 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4205 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4206 *
4207 * @pre This method can be called if @p scip is in one of the following stages:
4208 * - \ref SCIP_STAGE_SOLVING
4209 *
4210 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
4211 */
4213 SCIP* scip, /**< SCIP data structure */
4214 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4215 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
4216 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
4217 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
4218 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4219 int maxtestdelta, /**< maximum number of deltas to test */
4220 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
4221 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
4222 * NULL for using closest bound for all variables */
4223 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
4224 * NULL for using closest bound for all variables */
4225 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4226 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
4227 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
4228 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
4229 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
4230 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
4231 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
4232 SCIP_Real* cutefficacy, /**< pointer to store efficacy of best cut; only cuts that are strictly better than the value of
4233 * this efficacy on input to this function are returned */
4234 int* cutrank, /**< pointer to return rank of generated cut (or NULL) */
4235 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
4236 SCIP_Bool* success /**< pointer to store whether a valid and efficacious cut was returned */
4237 )
4238{
4239 int i;
4240 int firstcontvar;
4241 int nvars;
4242 int intstart;
4243 int ntmpcoefs;
4244 int* varsign;
4245 int* boundtype;
4246 int* mksetinds;
4247 SCIP_Real* mksetcoefs;
4248 SCIP_Real QUAD(mksetrhs);
4249 int mksetnnz;
4250 SCIP_Real* bounddist;
4251 int* bounddistpos;
4252 int nbounddist;
4253 SCIP_Real* tmpcoefs;
4254 SCIP_Real* tmpvalues;
4255 SCIP_Real* deltacands;
4256 int ndeltacands;
4257 SCIP_Real bestdelta;
4258 SCIP_Real bestefficacy;
4259 SCIP_Real maxabsmksetcoef;
4260 SCIP_VAR** vars;
4261 SCIP_Bool freevariable;
4262 SCIP_Bool localbdsused;
4263 SCIP_Real contactivity;
4264 SCIP_Real contsqrnorm;
4265
4266 assert(aggrrow != NULL);
4267 assert(aggrrow->nrows + aggrrow->nnz >= 1);
4268 assert(success != NULL);
4269
4270 *success = FALSE;
4271 nvars = SCIPgetNVars(scip);
4272 firstcontvar = nvars - SCIPgetNContVars(scip);
4273 vars = SCIPgetVars(scip);
4274
4275 /* allocate temporary memory */
4276 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
4277 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
4279 SCIP_CALL( SCIPallocBufferArray(scip, &mksetinds, nvars) );
4280 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, nvars + aggrrow->nrows) );
4281 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars + aggrrow->nrows) );
4282 SCIP_CALL( SCIPallocBufferArray(scip, &deltacands, aggrrow->nnz + 6) );
4283
4284 /* we only compute bound distance for integer variables; we allocate an array of length aggrrow->nnz to store this, since
4285 * this is the largest number of integer variables. (in contrast to the number of total variables which can be 2 *
4286 * aggrrow->nnz variables: if all are continuous and we use variable bounds to completement, we introduce aggrrow->nnz
4287 * extra vars)
4288 */
4289 SCIP_CALL( SCIPallocBufferArray(scip, &bounddist, aggrrow->nnz) );
4290 SCIP_CALL( SCIPallocBufferArray(scip, &bounddistpos, aggrrow->nnz) );
4291
4292 /* initialize mkset with aggregation */
4293 mksetnnz = aggrrow->nnz;
4294 QUAD_ASSIGN_Q(mksetrhs, aggrrow->rhs);
4295
4296 BMScopyMemoryArray(mksetinds, aggrrow->inds, mksetnnz);
4297
4298 for( i = 0; i < mksetnnz; ++i )
4299 {
4300 int j = mksetinds[i];
4301 SCIP_Real QUAD(coef);
4302 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
4303 QUAD_ARRAY_STORE(mksetcoefs, j, coef);
4304 assert(QUAD_HI(coef) != 0.0);
4305 }
4306
4307 *cutislocal = aggrrow->local;
4308
4309 /* Transform equation a*x == b, lb <= x <= ub into standard form
4310 * a'*x' == b, 0 <= x' <= ub'.
4311 *
4312 * Transform variables (lb or ub):
4313 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
4314 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
4315 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
4316 *
4317 * Transform variables (vlb or vub):
4318 * 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.
4319 * 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.
4320 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
4321 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
4322 * a_{zu_j} := a_{zu_j} + a_j * bu_j
4323 */
4324 SCIP_CALL( cutsTransformMIR(scip, sol, boundswitch, usevbds, allowlocal, FALSE, FALSE,
4325 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, varsign, boundtype, &freevariable, &localbdsused) );
4326
4327 assert(allowlocal || !localbdsused);
4328
4329 if( freevariable )
4330 goto TERMINATE;
4331
4332 SCIPdebugMsg(scip, "transformed aggrrow row:\n");
4333 SCIPdebug( printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE) );
4334
4335 /* found positions of integral variables that are strictly between their bounds */
4336 maxabsmksetcoef = -1.0;
4337 nbounddist = 0;
4338
4339 for( i = mksetnnz - 1; i >= 0 && mksetinds[i] < firstcontvar; --i )
4340 {
4341 SCIP_VAR* var = vars[mksetinds[i]];
4342 SCIP_Real primsol = SCIPgetSolVal(scip, sol, var);
4343 SCIP_Real lb = SCIPvarGetLbLocal(var);
4344 SCIP_Real ub = SCIPvarGetUbLocal(var);
4345 SCIP_Real QUAD(coef);
4346
4347 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4348
4349 if( SCIPisEQ(scip, primsol, lb) || SCIPisEQ(scip, primsol, ub) )
4350 continue;
4351
4352 bounddist[nbounddist] = MIN(ub - primsol, primsol - lb);
4353 bounddistpos[nbounddist] = i;
4354 deltacands[nbounddist] = QUAD_TO_DBL(coef);
4355 ++nbounddist;
4356 }
4357
4358 /* no fractional variable; so abort here */
4359 if( nbounddist == 0 )
4360 goto TERMINATE;
4361
4362 intstart = i + 1;
4363 ndeltacands = nbounddist;
4364
4365 SCIPsortDownRealRealInt(bounddist, deltacands, bounddistpos, nbounddist);
4366
4367 {
4368 SCIP_Real intscale;
4369 SCIP_Bool intscalesuccess;
4370
4371 SCIP_CALL( SCIPcalcIntegralScalar(deltacands, nbounddist, -SCIPepsilon(scip), SCIPsumepsilon(scip), (SCIP_Longint)10000, 10000.0, &intscale, &intscalesuccess) );
4372
4373 if( intscalesuccess )
4374 {
4375 SCIP_Real intf0;
4376 SCIP_Real intscalerhs;
4377 SCIP_Real delta;
4378
4379 intscalerhs = QUAD_TO_DBL(mksetrhs) * intscale;
4380 delta = 1.0 / intscale;
4381 intf0 = intscalerhs - floor(intscalerhs);
4382
4383 if( ! SCIPisFeasIntegral(scip, intf0) )
4384 {
4385 if( intf0 < minfrac || intf0 > maxfrac )
4386 {
4387 intscale *= SCIPceil(scip, MAX(minfrac, (1.0 - maxfrac)) / MIN(intf0, (1.0 - intf0)));
4388 intscalerhs = QUAD_TO_DBL(mksetrhs) * intscale;
4389 delta = 1.0 / intscale;
4390 intf0 = intscalerhs - floor(intscalerhs);
4391 }
4392
4393 if( intf0 >= minfrac && intf0 <= maxfrac )
4394 {
4395 if( ! SCIPisEQ(scip, delta, 1.0) )
4396 deltacands[ndeltacands++] = delta;
4397
4398 if( intf0 < maxfrac )
4399 {
4400 SCIP_Real delta2;
4401
4402 delta2 = 1.0 / (intscale * SCIPfloor(scip, maxfrac / intf0));
4403
4404 if( ! SCIPisEQ(scip, delta, delta2) && ! SCIPisEQ(scip, delta2, 1.0) )
4405 deltacands[ndeltacands++] = delta2;
4406 }
4407 }
4408 }
4409 }
4410 }
4411
4412 for( i = 0; i < nbounddist; ++i )
4413 {
4414 SCIP_Real absmksetcoef;
4415
4416 absmksetcoef = REALABS(deltacands[i]);
4417 maxabsmksetcoef = MAX(absmksetcoef, maxabsmksetcoef);
4418
4419 deltacands[i] = absmksetcoef;
4420 }
4421
4422 /* also test 1.0 and maxabsmksetcoef + 1.0 as last delta values */
4423 if( maxabsmksetcoef != -1.0 )
4424 deltacands[ndeltacands++] = maxabsmksetcoef + 1.0;
4425
4426 deltacands[ndeltacands++] = 1.0;
4427
4428 maxtestdelta = MIN(ndeltacands, maxtestdelta);
4429
4430 /* For each delta
4431 * Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
4432 * a~*x' <= down(b)
4433 * integers : a~_j = down(a'_j) , if f_j <= f_0
4434 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
4435 * continuous: a~_j = 0 , if a'_j >= 0
4436 * a~_j = a'_j/(1 - f0) , if a'_j < 0
4437 *
4438 * Transform inequality back to a^*x <= rhs:
4439 *
4440 * (lb or ub):
4441 * 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
4442 * 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
4443 * and move the constant terms
4444 * -a~_j * lb_j == -a^_j * lb_j, or
4445 * a~_j * ub_j == -a^_j * ub_j
4446 * to the rhs.
4447 *
4448 * (vlb or vub):
4449 * 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)
4450 * 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)
4451 * move the constant terms
4452 * -a~_j * dl_j == -a^_j * dl_j, or
4453 * a~_j * du_j == -a^_j * du_j
4454 * to the rhs, and update the VB variable coefficients:
4455 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
4456 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
4457 */
4458
4459 ntmpcoefs = 0;
4460 for( i = intstart; i < mksetnnz; ++i )
4461 {
4462 SCIP_VAR* var;
4463 SCIP_Real solval;
4464 SCIP_Real QUAD(coef);
4465
4466 var = vars[mksetinds[i]];
4467
4468 /* get the soltion value of the continuous variable */
4469 solval = SCIPgetSolVal(scip, sol, var);
4470
4471 /* now compute the solution value in the transform space considering complementation */
4472 if( boundtype[i] == -1 )
4473 {
4474 /* variable was complemented with global (simple) bound */
4475 if( varsign[i] == -1 )
4476 solval = SCIPvarGetUbGlobal(var) - solval;
4477 else
4478 solval = solval - SCIPvarGetLbGlobal(var);
4479 }
4480 else
4481 {
4482 assert(boundtype[i] == -2);
4483
4484 /* variable was complemented with local (simple) bound */
4485 if( varsign[i] == -1 )
4486 solval = SCIPvarGetUbLocal(var) - solval;
4487 else
4488 solval = solval - SCIPvarGetLbLocal(var);
4489 }
4490
4491 tmpvalues[ntmpcoefs] = solval;
4492 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4493 tmpcoefs[ntmpcoefs] = varsign[i] * QUAD_TO_DBL(coef);
4494 ++ntmpcoefs;
4495 }
4496
4497 assert(ntmpcoefs == mksetnnz - intstart);
4498
4499 contactivity = 0.0;
4500 contsqrnorm = 0.0;
4501 for( i = 0; i < intstart; ++i )
4502 {
4503 SCIP_Real solval;
4504 SCIP_Real QUAD(mksetcoef);
4505
4506 QUAD_ARRAY_LOAD(mksetcoef, mksetcoefs, mksetinds[i]);
4507
4508 if( varsign[i] * QUAD_TO_DBL(mksetcoef) >= 0.0 )
4509 continue;
4510
4511 /* get the soltion value of the continuous variable */
4512 solval = SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
4513
4514 /* now compute the solution value in the transform space considering complementation */
4515 switch( boundtype[i] )
4516 {
4517 case -1:
4518 /* variable was complemented with global (simple) bound */
4519 if( varsign[i] == -1 )
4520 solval = SCIPvarGetUbGlobal(vars[mksetinds[i]]) - solval;
4521 else
4522 solval = solval - SCIPvarGetLbGlobal(vars[mksetinds[i]]);
4523 break;
4524 case -2:
4525 /* variable was complemented with local (simple) bound */
4526 if( varsign[i] == -1 )
4527 solval = SCIPvarGetUbLocal(vars[mksetinds[i]]) - solval;
4528 else
4529 solval = solval - SCIPvarGetLbLocal(vars[mksetinds[i]]);
4530 break;
4531 default:
4532 /* variable was complemented with a variable bound */
4533 if( varsign[i] == -1 )
4534 {
4535 SCIP_Real coef;
4536 SCIP_Real constant;
4537 SCIP_Real vbdsolval;
4538
4539 coef = SCIPvarGetVubCoefs(vars[mksetinds[i]])[boundtype[i]];
4540 constant = SCIPvarGetVubConstants(vars[mksetinds[i]])[boundtype[i]];
4541 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVubVars(vars[mksetinds[i]])[boundtype[i]]);
4542
4543 solval = (coef * vbdsolval + constant) - solval;
4544 }
4545 else
4546 {
4547 SCIP_Real coef;
4548 SCIP_Real constant;
4549 SCIP_Real vbdsolval;
4550
4551 coef = SCIPvarGetVlbCoefs(vars[mksetinds[i]])[boundtype[i]];
4552 constant = SCIPvarGetVlbConstants(vars[mksetinds[i]])[boundtype[i]];
4553 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVlbVars(vars[mksetinds[i]])[boundtype[i]]);
4554
4555 solval = solval - (coef * vbdsolval + constant);
4556 }
4557 }
4558
4559 contactivity += solval * (QUAD_TO_DBL(mksetcoef) * varsign[i]);
4560 contsqrnorm += QUAD_TO_DBL(mksetcoef) * QUAD_TO_DBL(mksetcoef);
4561 }
4562
4563 {
4564 SCIP_ROW** rows;
4565
4566 rows = SCIPgetLPRows(scip);
4567
4568 for( i = 0; i < aggrrow->nrows; ++i )
4569 {
4570 SCIP_ROW* row;
4571 SCIP_Real slackval;
4572
4573 row = rows[aggrrow->rowsinds[i]];
4574
4575 if( (aggrrow->rowweights[i] * aggrrow->slacksign[i]) >= 0.0 && !row->integral )
4576 continue;
4577
4578 /* compute solution value of slack variable */
4579 slackval = SCIPgetRowSolActivity(scip, row, sol);
4580
4581 if( aggrrow->slacksign[i] == +1 )
4582 {
4583 /* right hand side */
4584 assert(!SCIPisInfinity(scip, row->rhs));
4585
4586 slackval = row->rhs - slackval;
4587 }
4588 else
4589 {
4590 /* left hand side */
4591 assert(aggrrow->slacksign[i] == -1);
4592 assert(!SCIPisInfinity(scip, -row->lhs));
4593
4594 slackval = slackval - row->lhs;
4595 }
4596
4597 if( row->integral )
4598 {
4599 /* if row is integral add variable to tmp arrays */
4600 tmpvalues[ntmpcoefs] = slackval;
4601 tmpcoefs[ntmpcoefs] = aggrrow->rowweights[i] * aggrrow->slacksign[i];
4602 ++ntmpcoefs;
4603 }
4604 else
4605 {
4606 SCIP_Real slackcoeff = (aggrrow->rowweights[i] * aggrrow->slacksign[i]);
4607
4608 /* otherwise add it to continuous activity */
4609 contactivity += slackval * slackcoeff;
4610 contsqrnorm += SQR(slackcoeff);
4611 }
4612 }
4613 }
4614
4615 /* try all candidates for delta and remember best */
4616 bestdelta = SCIP_INVALID;
4617 bestefficacy = -SCIPinfinity(scip);
4618
4619 for( i = 0; i < maxtestdelta; ++i )
4620 {
4621 int j;
4622 SCIP_Real efficacy;
4623
4624 /* check if we have seen this value of delta before */
4625 SCIP_Bool deltaseenbefore = FALSE;
4626 for( j = 0; j < i; ++j )
4627 {
4628 if( SCIPisEQ(scip, deltacands[i], deltacands[j]) )
4629 {
4630 deltaseenbefore = TRUE;
4631 break;
4632 }
4633 }
4634
4635 /* skip this delta value and allow one more delta value if available */
4636 if( deltaseenbefore )
4637 {
4638 maxtestdelta = MIN(maxtestdelta + 1, ndeltacands);
4639 continue;
4640 }
4641
4642 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, deltacands[i], ntmpcoefs, minfrac, maxfrac);
4643
4644 if( efficacy > bestefficacy )
4645 {
4646 bestefficacy = efficacy;
4647 bestdelta = deltacands[i];
4648 }
4649 }
4650
4651 /* no delta was found that yielded any cut */
4652 if( bestdelta == SCIP_INVALID ) /*lint !e777*/
4653 goto TERMINATE;
4654
4655 /* try bestdelta divided by 2, 4 and 8 */
4656 {
4657 SCIP_Real basedelta = bestdelta;
4658 for( i = 2; i <= 8 ; i *= 2 )
4659 {
4660 SCIP_Real efficacy;
4661 SCIP_Real delta;
4662
4663 delta = basedelta / i;
4664
4665 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, delta, ntmpcoefs, minfrac, maxfrac);
4666
4667 if( efficacy > bestefficacy )
4668 {
4669 bestefficacy = efficacy;
4670 bestdelta = delta;
4671 }
4672 }
4673 }
4674
4675 /* try to improve efficacy by switching complementation of integral variables that are not at their bounds
4676 * in order of non-increasing bound distance
4677 */
4678 for( i = 0; i < nbounddist; ++i )
4679 {
4680 int k;
4681 SCIP_Real newefficacy;
4682 SCIP_Real QUAD(newrhs);
4683 SCIP_Real QUAD(quadprod);
4684 SCIP_Real bestlb;
4685 SCIP_Real bestub;
4686 SCIP_Real oldsolval;
4687 SCIP_Real simplebnd;
4688 int bestlbtype;
4689 int bestubtype;
4690
4691 k = bounddistpos[i];
4692
4693 SCIP_CALL( findBestLb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestlb, &simplebnd, &bestlbtype) );
4694
4695 if( SCIPisInfinity(scip, -bestlb) )
4696 continue;
4697
4698 SCIP_CALL( findBestUb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestub, &simplebnd, &bestubtype) );
4699
4700 if( SCIPisInfinity(scip, bestub) )
4701 continue;
4702
4703 /* switch the complementation of this variable */
4704#ifndef NDEBUG
4705 {
4706 SCIP_Real QUAD(coef);
4707 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[k]);
4708 assert(SCIPisEQ(scip, tmpcoefs[k - intstart], varsign[k] * QUAD_TO_DBL(coef)));
4709 }
4710#endif
4711
4712 /* compute this: newrhs = mksetrhs + tmpcoefs[k - intstart] * (bestlb - bestub); */
4713 SCIPquadprecProdDD(quadprod, tmpcoefs[k - intstart], bestlb - bestub);
4714 SCIPquadprecSumQQ(newrhs, mksetrhs, quadprod);
4715 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
4716
4717 oldsolval = tmpvalues[k - intstart];
4718 tmpvalues[k - intstart] = varsign[k] == +1 ? bestub - SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) : SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) - bestlb;
4719
4720 /* compute new violation */
4721 newefficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(newrhs), contactivity, contsqrnorm, bestdelta, ntmpcoefs, minfrac, maxfrac);
4722
4723 /* check if violaton was increased */
4724 if( newefficacy > bestefficacy )
4725 {
4726 /* keep change of complementation */
4727 bestefficacy = newefficacy;
4728 QUAD_ASSIGN_Q(mksetrhs, newrhs);
4729
4730 if( varsign[k] == +1 )
4731 {
4732 /* switch to upper bound */
4733 assert(bestubtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4734 boundtype[k] = bestubtype;
4735 varsign[k] = -1;
4736 }
4737 else
4738 {
4739 /* switch to lower bound */
4740 assert(bestlbtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4741 boundtype[k] = bestlbtype;
4742 varsign[k] = +1;
4743 }
4744
4745 localbdsused = localbdsused || (boundtype[k] == -2);
4746 }
4747 else
4748 {
4749 /* undo the change of the complementation */
4750 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
4751 tmpvalues[k - intstart] = oldsolval;
4752 }
4753 } /*lint !e438*/
4754
4755 if( bestefficacy > 0.0 )
4756 {
4757 SCIP_Real mirefficacy;
4758 SCIP_Real QUAD(downrhs);
4759 SCIP_Real QUAD(f0);
4760 SCIP_Real scale;
4761
4762 scale = 1.0 / bestdelta;
4763 SCIPquadprecProdQD(mksetrhs, mksetrhs, scale);
4764 SCIPquadprecEpsFloorQ(downrhs, mksetrhs, SCIPepsilon(scip)); /*lint !e666*/
4765 SCIPquadprecSumQQ(f0, mksetrhs, -downrhs);
4766 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
4767
4768 /* renormaliize f0 value */
4769 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
4770
4771 for( i = 0; i < mksetnnz; ++i )
4772 {
4773 SCIP_Real QUAD(coef);
4774
4775 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4776 SCIPquadprecProdQD(coef, coef, scale);
4777 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], coef);
4778 }
4779 SCIPdebugMsg(scip, "applied best scale (=%.13g):\n", scale);
4780 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4781
4782 QUAD_ASSIGN_Q(mksetrhs, downrhs);
4783
4784 SCIP_CALL( cutsRoundMIR(scip, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, varsign, boundtype, QUAD(f0)) );
4785
4786 SCIPdebugMsg(scip, "rounded MIR cut:\n");
4787 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4788
4789 /* substitute aggregated slack variables:
4790 *
4791 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
4792 * variable only appears in its own row:
4793 * a'_r = scale * weight[r] * slacksign[r].
4794 *
4795 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
4796 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
4797 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
4798 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
4799 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
4800 *
4801 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
4802 */
4803 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
4804 aggrrow->nrows, scale, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, QUAD(f0)) );
4805
4806 SCIPdebugMsg(scip, "substituted slacks in MIR cut:\n");
4807 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4808
4809#ifndef NDEBUG
4810 {
4811 SCIP_Real efficacy = -QUAD_TO_DBL(mksetrhs);
4812 for( i = 0; i < mksetnnz; ++i )
4813 {
4814 SCIP_Real QUAD(coef);
4815 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4816 efficacy += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
4817 }
4818
4819 if( !EPSZ(SCIPrelDiff(efficacy, bestefficacy), 1e-4) )
4820 {
4821 SCIPdebugMsg(scip, "efficacy of cmir cut is different than expected efficacy: %f != %f\n", efficacy, bestefficacy);
4822 }
4823 }
4824#endif
4825
4826 *cutislocal = *cutislocal || localbdsused;
4827
4828 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
4829 * prevent numerical rounding errors
4830 */
4831 if( postprocess )
4832 {
4833 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, mksetinds, mksetcoefs, &mksetnnz, QUAD(&mksetrhs), success) );
4834 }
4835 else
4836 {
4837 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz);
4838 }
4839
4840 SCIPdebugMsg(scip, "post-processed cut (success = %s):\n", *success ? "TRUE" : "FALSE");
4841 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4842
4843 if( *success )
4844 {
4845 mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, mksetcoefs, QUAD_TO_DBL(mksetrhs), mksetinds, mksetnnz);
4846
4847 if( SCIPisEfficacious(scip, mirefficacy) && mirefficacy > *cutefficacy )
4848 {
4849 BMScopyMemoryArray(cutinds, mksetinds, mksetnnz);
4850 for( i = 0; i < mksetnnz; ++i )
4851 {
4852 SCIP_Real QUAD(coef);
4853 int j = cutinds[i];
4854
4855 QUAD_ARRAY_LOAD(coef, mksetcoefs, j);
4856
4857 cutcoefs[i] = QUAD_TO_DBL(coef);
4858 QUAD_ASSIGN(coef, 0.0);
4859 QUAD_ARRAY_STORE(mksetcoefs, j, coef);
4860 }
4861 *cutnnz = mksetnnz;
4862 *cutrhs = QUAD_TO_DBL(mksetrhs);
4863 *cutefficacy = mirefficacy;
4864 if( cutrank != NULL )
4865 *cutrank = aggrrow->rank + 1;
4866 *cutislocal = *cutislocal || localbdsused;
4867 }
4868 else
4869 *success = FALSE;
4870 }
4871 }
4872
4873 TERMINATE:
4874 /* if we aborted early we need to clean the mksetcoefs */
4875 if( !(*success) )
4876 {
4877 SCIP_Real QUAD(tmp);
4878 QUAD_ASSIGN(tmp, 0.0);
4879
4880 for( i = 0; i < mksetnnz; ++i )
4881 {
4882 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], tmp);
4883 }
4884 }
4885
4886 /* free temporary memory */
4887 SCIPfreeBufferArray(scip, &bounddistpos);
4888 SCIPfreeBufferArray(scip, &bounddist);
4889 SCIPfreeBufferArray(scip, &deltacands);
4890 SCIPfreeBufferArray(scip, &tmpvalues);
4891 SCIPfreeBufferArray(scip, &tmpcoefs);
4892 SCIPfreeBufferArray(scip, &mksetinds);
4893 SCIPfreeCleanBufferArray(scip, &mksetcoefs);
4894 SCIPfreeBufferArray(scip, &boundtype);
4895 SCIPfreeBufferArray(scip, &varsign);
4896
4897 return SCIP_OKAY;
4898}
4899
4900/* =========================================== flow cover =========================================== */
4901
4902#define NO_EXACT_KNAPSACK
4903
4904#ifndef NO_EXACT_KNAPSACK
4905#define MAXDNOM 1000LL
4906#define MINDELTA 1e-03
4907#define MAXDELTA 1e-09
4908#define MAXSCALE 1000.0
4909#define MAXDYNPROGSPACE 1000000
4910#endif
4911
4912#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for snf relaxation */
4913#define MAXBOUND 1e+10 /**< maximal value of normal bounds used for snf relaxation */
4914
4915/** structure that contains all data required to perform the sequence independent lifting
4916 */
4917typedef
4918struct LiftingData
4919{
4920 SCIP_Real* M; /**< \f$ M_0 := 0.0 \f$ and \f$ M_i := M_i-1 + m_i \f$ */
4921 SCIP_Real* m; /**< non-increasing array of variable upper bound coefficients
4922 * for all variables in \f$ C^{++} \f$ and \f$ L^- \f$,
4923 * where \f$ C = C^+ \cup C^- \f$ is the flowcover and
4924 * \f$ C^{++} := \{ j \in C^+ \mid u_j > \lambda \} \f$
4925 * \f$ L^- := \{ j \in (N^- \setminus C^-) \mid u_j > \lambda \} \f$
4926 */
4927 int r; /**< size of array m */
4928 int t; /**< index of smallest value in m that comes from a variable in \f$ C^{++} \f$ */
4929 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$ */
4930 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$ */
4931 SCIP_Real lambda; /**< excess of the flowcover */
4932 SCIP_Real mp; /**< smallest variable bound coefficient of variable in \f$ C^{++} (min_{j \in C++} u_j) \f$ */
4933 SCIP_Real ml; /**< \f$ ml := min(\lambda, \sum_{j \in C^+ \setminus C^{++}} u_j) \f$ */
4935
4936/** structure that contains all the data that defines the single-node-flow relaxation of an aggregation row */
4937typedef
4938struct SNF_Relaxation
4939{
4940 int* transvarcoefs; /**< coefficients of all vars in relaxed set */
4941 SCIP_Real* transbinvarsolvals; /**< sol val of bin var in vub of all vars in relaxed set */
4942 SCIP_Real* transcontvarsolvals;/**< sol val of all real vars in relaxed set */
4943 SCIP_Real* transvarvubcoefs; /**< coefficient in vub of all vars in relaxed set */
4944 int ntransvars; /**< number of vars in relaxed set */
4945 SCIP_Real transrhs; /**< rhs in relaxed set */
4946 int* origbinvars; /**< associated original binary var for all vars in relaxed set */
4947 int* origcontvars; /**< associated original continuous var for all vars in relaxed set */
4948 SCIP_Real* aggrcoefsbin; /**< aggregation coefficient of the original binary var used to define the
4949 * continuous variable in the relaxed set */
4950 SCIP_Real* aggrcoefscont; /**< aggregation coefficient of the original continuous var used to define the
4951 * continuous variable in the relaxed set */
4952 SCIP_Real* aggrconstants; /**< aggregation constant used to define the continuous variable in the relaxed set */
4954
4955/** get solution value and index of variable lower bound (with binary variable) which is closest to the current LP
4956 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
4957 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
4958 * given variable
4959 */
4960static
4962 SCIP* scip, /**< SCIP data structure */
4963 SCIP_VAR* var, /**< given active problem variable */
4964 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
4965 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
4966 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
4967 * was not used (0) or was not used but is contained in the row (-1)
4968 */
4969 SCIP_Real bestsub, /**< closest simple upper bound of given variable */
4970 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
4971 SCIP_Real* closestvlb, /**< pointer to store the LP sol value of the closest variable lower bound */
4972 int* closestvlbidx /**< pointer to store the index of the closest vlb; -1 if no vlb was found */
4973 )
4974{
4975 int nvlbs;
4976 int nbinvars;
4977
4978 assert(scip != NULL);
4979 assert(var != NULL);
4980 assert(bestsub == SCIPvarGetUbGlobal(var) || bestsub == SCIPvarGetUbLocal(var)); /*lint !e777*/
4981 assert(!SCIPisInfinity(scip, bestsub));
4982 assert(!EPSZ(rowcoef, QUAD_EPSILON));
4983 assert(rowcoefs != NULL);
4984 assert(binvarused != NULL);
4985 assert(closestvlb != NULL);
4986 assert(closestvlbidx != NULL);
4987
4988 nvlbs = SCIPvarGetNVlbs(var);
4989 nbinvars = SCIPgetNBinVars(scip);
4990
4991 *closestvlbidx = -1;
4992 *closestvlb = -SCIPinfinity(scip);
4993 if( nvlbs > 0 )
4994 {
4995 SCIP_VAR** vlbvars;
4996 SCIP_Real* vlbcoefs;
4997 SCIP_Real* vlbconsts;
4998 int i;
4999
5000 vlbvars = SCIPvarGetVlbVars(var);
5001 vlbcoefs = SCIPvarGetVlbCoefs(var);
5002 vlbconsts = SCIPvarGetVlbConstants(var);
5003
5004 for( i = 0; i < nvlbs; i++ )
5005 {
5006 SCIP_Real rowcoefbinvar;
5007 SCIP_Real val1;
5008 SCIP_Real val2;
5009 SCIP_Real vlbsol;
5010 SCIP_Real rowcoefsign;
5011 int probidxbinvar;
5012
5013 if( bestsub > vlbconsts[i] )
5014 continue;
5015
5016 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
5017 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
5018 */
5019 if( REALABS(vlbcoefs[i]) > MAXABSVBCOEF )
5020 continue;
5021
5022 /* use only variable lower bounds l~_i * x_i + d_i with x_i binary which are active */
5023 probidxbinvar = SCIPvarGetProbindex(vlbvars[i]);
5024
5025 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
5026 * ensures that the problem index is between 0 and nbinvars - 1
5027 */
5028 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
5029 continue;
5030
5031 assert(SCIPvarIsBinary(vlbvars[i]));
5032
5033 /* check if current variable lower bound l~_i * x_i + d_i imposed on y_j meets the following criteria:
5034 * (let a_j = coefficient of y_j in current row,
5035 * u_j = closest simple upper bound imposed on y_j,
5036 * c_i = coefficient of x_i in current row)
5037 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k yet
5038 * if a_j > 0:
5039 * 1. u_j <= d_i
5040 * 2. a_j ( u_j - d_i ) + c_i <= 0
5041 * 3. a_j l~_i + c_i <= 0
5042 * if a_j < 0:
5043 * 1. u_j <= d_i
5044 * 2. a_j ( u_j - d_i ) + c_i >= 0
5045 * 3. a_j l~_i + c_i >= 0
5046 */
5047
5048 /* has already been used in the SNF relaxation */
5049 if( binvarused[probidxbinvar] == 1 )
5050 continue;
5051
5052 /* get the row coefficient */
5053 {
5054 SCIP_Real QUAD(tmp);
5055 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
5056 rowcoefbinvar = QUAD_TO_DBL(tmp);
5057 }
5058 rowcoefsign = COPYSIGN(1.0, rowcoef);
5059
5060 val2 = rowcoefsign * ((rowcoef * vlbcoefs[i]) + rowcoefbinvar);
5061
5062 /* variable lower bound does not meet criteria */
5063 if( val2 > 0.0 || SCIPisInfinity(scip, -val2) )
5064 continue;
5065
5066 val1 = rowcoefsign * ((rowcoef * (bestsub - vlbconsts[i])) + rowcoefbinvar);
5067
5068 /* variable lower bound does not meet criteria */
5069 if( val1 > 0.0 )
5070 continue;
5071
5072 vlbsol = vlbcoefs[i] * SCIPgetSolVal(scip, sol, vlbvars[i]) + vlbconsts[i];
5073 if( vlbsol > *closestvlb )
5074 {
5075 *closestvlb = vlbsol;
5076 *closestvlbidx = i;
5077 }
5078 assert(*closestvlbidx >= 0);
5079 }
5080 }
5081
5082 return SCIP_OKAY;
5083}
5084
5085/** get LP solution value and index of variable upper bound (with binary variable) which is closest to the current LP
5086 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
5087 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
5088 * given variable
5089 */
5090static
5092 SCIP* scip, /**< SCIP data structure */
5093 SCIP_VAR* var, /**< given active problem variable */
5094 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5095 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
5096 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5097 * was not used (0) or was not used but is contained in the row (-1)
5098 */
5099 SCIP_Real bestslb, /**< closest simple lower bound of given variable */
5100 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
5101 SCIP_Real* closestvub, /**< pointer to store the LP sol value of the closest variable upper bound */
5102 int* closestvubidx /**< pointer to store the index of the closest vub; -1 if no vub was found */
5103 )
5104{
5105 int nvubs;
5106 int nbinvars;
5107
5108 assert(scip != NULL);
5109 assert(var != NULL);
5110 assert(bestslb == SCIPvarGetLbGlobal(var) || bestslb == SCIPvarGetLbLocal(var)); /*lint !e777*/
5111 assert(!SCIPisInfinity(scip, - bestslb));
5112 assert(!EPSZ(rowcoef, QUAD_EPSILON));
5113 assert(rowcoefs != NULL);
5114 assert(binvarused != NULL);
5115 assert(closestvub != NULL);
5116 assert(closestvubidx != NULL);
5117
5118 nvubs = SCIPvarGetNVubs(var);
5119 nbinvars = SCIPgetNBinVars(scip);
5120
5121 *closestvubidx = -1;
5122 *closestvub = SCIPinfinity(scip);
5123 if( nvubs > 0 )
5124 {
5125 SCIP_VAR** vubvars;
5126 SCIP_Real* vubcoefs;
5127 SCIP_Real* vubconsts;
5128 int i;
5129
5130 vubvars = SCIPvarGetVubVars(var);
5131 vubcoefs = SCIPvarGetVubCoefs(var);
5132 vubconsts = SCIPvarGetVubConstants(var);
5133
5134 for( i = 0; i < nvubs; i++ )
5135 {
5136 SCIP_Real rowcoefbinvar;
5137 SCIP_Real val1;
5138 SCIP_Real val2;
5139 SCIP_Real vubsol;
5140 SCIP_Real rowcoefsign;
5141 int probidxbinvar;
5142
5143 if( bestslb < vubconsts[i] )
5144 continue;
5145
5146 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
5147 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
5148 */
5149 if( REALABS(vubcoefs[i]) > MAXABSVBCOEF )
5150 continue;
5151
5152 /* use only variable upper bound u~_i * x_i + d_i with x_i binary and which are active */
5153 probidxbinvar = SCIPvarGetProbindex(vubvars[i]);
5154
5155 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
5156 * ensures that the problem index is between 0 and nbinvars - 1
5157 */
5158 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
5159 continue;
5160
5161 assert(SCIPvarIsBinary(vubvars[i]));
5162
5163 /* checks if current variable upper bound u~_i * x_i + d_i meets the following criteria
5164 * (let a_j = coefficient of y_j in current row,
5165 * l_j = closest simple lower bound imposed on y_j,
5166 * c_i = coefficient of x_i in current row)
5167 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k
5168 * if a > 0:
5169 * 1. l_j >= d_i
5170 * 2. a_j ( l_i - d_i ) + c_i >= 0
5171 * 3. a_j u~_i + c_i >= 0
5172 * if a < 0:
5173 * 1. l_j >= d_i
5174 * 2. a_j ( l_j - d_i ) + c_i <= 0
5175 * 3. a_j u~_i + c_i <= 0
5176 */
5177
5178 /* has already been used in the SNF relaxation */
5179 if( binvarused[probidxbinvar] == 1 )
5180 continue;
5181
5182 /* get the row coefficient */
5183 {
5184 SCIP_Real QUAD(tmp);
5185 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
5186 rowcoefbinvar = QUAD_TO_DBL(tmp);
5187 }
5188 rowcoefsign = COPYSIGN(1.0, rowcoef);
5189
5190 val2 = rowcoefsign * ((rowcoef * vubcoefs[i]) + rowcoefbinvar);
5191
5192 /* variable upper bound does not meet criteria */
5193 if( val2 < 0.0 || SCIPisInfinity(scip, val2) )
5194 continue;
5195
5196 val1 = rowcoefsign * ((rowcoef * (bestslb - vubconsts[i])) + rowcoefbinvar);
5197
5198 /* variable upper bound does not meet criteria */
5199 if( val1 < 0.0 )
5200 continue;
5201
5202 vubsol = vubcoefs[i] * SCIPgetSolVal(scip, sol, vubvars[i]) + vubconsts[i];
5203 if( vubsol < *closestvub )
5204 {
5205 *closestvub = vubsol;
5206 *closestvubidx = i;
5207 }
5208 assert(*closestvubidx >= 0);
5209 }
5210 }
5211
5212 return SCIP_OKAY;
5213}
5214
5215/** determines the bounds to use for constructing the single-node-flow relaxation of a variable in
5216 * the given row.
5217 */
5218static
5220 SCIP* scip, /**< SCIP data structure */
5221 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5222 SCIP_VAR** vars, /**< array of problem variables */
5223 SCIP_Real* rowcoefs, /**< (dense) array of variable coefficients in the row */
5224 int* rowinds, /**< array with positions of non-zero values in the rowcoefs array */
5225 int varposinrow, /**< position of variable in the rowinds array for which the bounds should be determined */
5226 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5227 * was not used (0) or was not used but is contained in the row (-1)
5228 */
5229 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5230 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5231 SCIP_Real* bestlb, /**< pointer to store best lower bound for transformation */
5232 SCIP_Real* bestub, /**< pointer to store best upper bound for transformation */
5233 SCIP_Real* bestslb, /**< pointer to store best simple lower bound for transformation */
5234 SCIP_Real* bestsub, /**< pointer to store best simple upper bound for transformation */
5235 int* bestlbtype, /**< pointer to store type of best lower bound */
5236 int* bestubtype, /**< pointer to store type of best upper bound */
5237 int* bestslbtype, /**< pointer to store type of best simple lower bound */
5238 int* bestsubtype, /**< pointer to store type of best simple upper bound */
5239 SCIP_BOUNDTYPE* selectedbounds, /**< pointer to store the preferred bound for the transformation */
5240 SCIP_Bool* freevariable /**< pointer to store if variable is a free variable */
5241 )
5242{
5243 SCIP_VAR* var;
5244
5245 SCIP_Real rowcoef;
5246 SCIP_Real solval;
5247 SCIP_Real simplebound;
5248
5249 int probidx;
5250
5251 bestlb[varposinrow] = -SCIPinfinity(scip);
5252 bestub[varposinrow] = SCIPinfinity(scip);
5253 bestlbtype[varposinrow] = -3;
5254 bestubtype[varposinrow] = -3;
5255
5256 probidx = rowinds[varposinrow];
5257 var = vars[probidx];
5258 {
5259 SCIP_Real QUAD(tmp);
5260 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidx);
5261 rowcoef = QUAD_TO_DBL(tmp);
5262 }
5263
5264 assert(!EPSZ(rowcoef, QUAD_EPSILON));
5265
5266 /* get closest simple lower bound and closest simple upper bound */
5267 SCIP_CALL( findBestLb(scip, var, sol, 0, allowlocal, &bestslb[varposinrow], &simplebound, &bestslbtype[varposinrow]) );
5268 SCIP_CALL( findBestUb(scip, var, sol, 0, allowlocal, &bestsub[varposinrow], &simplebound, &bestsubtype[varposinrow]) );
5269
5270 /* do not use too large bounds */
5271 if( bestslb[varposinrow] <= -MAXBOUND )
5272 bestslb[varposinrow] = -SCIPinfinity(scip);
5273
5274 if( bestsub[varposinrow] >= MAXBOUND )
5275 bestsub[varposinrow] = SCIPinfinity(scip);
5276
5277 solval = SCIPgetSolVal(scip, sol, var);
5278
5279 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g(%d),%g(%d)]>:\n", varposinrow, rowcoef, SCIPvarGetName(var), probidx,
5280 solval, bestslb[varposinrow], bestslbtype[varposinrow], bestsub[varposinrow], bestsubtype[varposinrow]);
5281
5282 /* mixed integer set cannot be relaxed to 0-1 single node flow set because both simple bounds are -infinity
5283 * and infinity, respectively
5284 */
5285 if( SCIPisInfinity(scip, -bestslb[varposinrow]) && SCIPisInfinity(scip, bestsub[varposinrow]) )
5286 {
5287 *freevariable = TRUE;
5288 return SCIP_OKAY;
5289 }
5290
5291 /* get closest lower bound that can be used to define the real variable y'_j in the 0-1 single node flow
5292 * relaxation
5293 */
5294 if( !SCIPisInfinity(scip, bestsub[varposinrow]) )
5295 {
5296 bestlb[varposinrow] = bestslb[varposinrow];
5297 bestlbtype[varposinrow] = bestslbtype[varposinrow];
5298
5300 {
5301 SCIP_Real bestvlb;
5302 int bestvlbidx;
5303
5304 SCIP_CALL( getClosestVlb(scip, var, sol, rowcoefs, binvarused, bestsub[varposinrow], rowcoef, &bestvlb, &bestvlbidx) );
5305 if( SCIPisGT(scip, bestvlb, bestlb[varposinrow]) )
5306 {
5307 bestlb[varposinrow] = bestvlb;
5308 bestlbtype[varposinrow] = bestvlbidx;
5309 }
5310 }
5311 }
5312
5313 /* get closest upper bound that can be used to define the real variable y'_j in the 0-1 single node flow
5314 * relaxation
5315 */
5316 if( !SCIPisInfinity(scip, -bestslb[varposinrow]) )
5317 {
5318 bestub[varposinrow] = bestsub[varposinrow];
5319 bestubtype[varposinrow] = bestsubtype[varposinrow];
5320
5322 {
5323 SCIP_Real bestvub;
5324 int bestvubidx;
5325
5326 SCIP_CALL( getClosestVub(scip, var, sol, rowcoefs, binvarused, bestslb[varposinrow], rowcoef, &bestvub, &bestvubidx) );
5327 if( SCIPisLT(scip, bestvub, bestub[varposinrow]) )
5328 {
5329 bestub[varposinrow] = bestvub;
5330 bestubtype[varposinrow] = bestvubidx;
5331 }
5332 }
5333 }
5334 SCIPdebugMsg(scip, " bestlb=%g(%d), bestub=%g(%d)\n", bestlb[varposinrow], bestlbtype[varposinrow], bestub[varposinrow], bestubtype[varposinrow]);
5335
5336 /* mixed integer set cannot be relaxed to 0-1 single node flow set because there are no suitable bounds
5337 * to define the transformed variable y'_j
5338 */
5339 if( SCIPisInfinity(scip, -bestlb[varposinrow]) && SCIPisInfinity(scip, bestub[varposinrow]) )
5340 {
5341 *freevariable = TRUE;
5342 return SCIP_OKAY;
5343 }
5344
5345 *freevariable = FALSE;
5346
5347 /* select best upper bound if it is closer to the LP value of y_j and best lower bound otherwise and use this bound
5348 * to define the real variable y'_j with 0 <= y'_j <= u'_j x_j in the 0-1 single node flow relaxation;
5349 * prefer variable bounds
5350 */
5351 if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) && bestlbtype[varposinrow] >= 0 )
5352 {
5353 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
5354 }
5355 else if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow])
5356 && bestubtype[varposinrow] >= 0 )
5357 {
5358 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
5359 }
5360 else if( SCIPisLE(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) )
5361 {
5362 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
5363 }
5364 else
5365 {
5366 assert(SCIPisGT(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]));
5367 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
5368 }
5369
5370 if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_LOWER && bestlbtype[varposinrow] >= 0 )
5371 {
5372 int vlbvarprobidx;
5373 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
5374
5375 /* mark binary variable of vlb so that it is not used for other continuous variables
5376 * by setting it's position in the aggrrow to a negative value
5377 */
5378 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[varposinrow]]);
5379 binvarused[vlbvarprobidx] = 1;
5380 }
5381 else if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_UPPER && bestubtype[varposinrow] >= 0 )
5382 {
5383 int vubvarprobidx;
5384 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
5385
5386 /* mark binary variable of vub so that it is not used for other continuous variables
5387 * by setting it's position in the aggrrow to a negative value
5388 */
5389 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[varposinrow]]);
5390 binvarused[vubvarprobidx] = 1;
5391 }
5392
5393 return SCIP_OKAY; /*lint !e438*/
5394}
5395
5396/** construct a 0-1 single node flow relaxation (with some additional simple constraints) of a mixed integer set
5397 * corresponding to the given aggrrow a * x <= rhs
5398 */
5399static
5401 SCIP* scip, /**< SCIP data structure */
5402 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
5403 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5404 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5405 SCIP_Real* rowcoefs, /**< array of coefficients of row */
5406 QUAD(SCIP_Real rowrhs), /**< pointer to right hand side of row */
5407 int* rowinds, /**< array of variables problem indices for non-zero coefficients in row */
5408 int nnz, /**< number of non-zeros in row */
5409 SNF_RELAXATION* snf, /**< stores the sign of the transformed variable in summation */
5410 SCIP_Bool* success, /**< stores whether the transformation was valid */
5411 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
5412 )
5413{
5414 SCIP_VAR** vars;
5415 int i;
5416 int nnonbinvarsrow;
5417 int8_t* binvarused;
5418 int nbinvars;
5419 SCIP_Real QUAD(transrhs);
5420
5421 /* arrays to store the selected bound for each non-binary variable in the row */
5422 SCIP_Real* bestlb;
5423 SCIP_Real* bestub;
5424 SCIP_Real* bestslb;
5425 SCIP_Real* bestsub;
5426 int* bestlbtype;
5427 int* bestubtype;
5428 int* bestslbtype;
5429 int* bestsubtype;
5430 SCIP_BOUNDTYPE* selectedbounds;
5431
5432 *success = FALSE;
5433
5434 SCIPdebugMsg(scip, "--------------------- construction of SNF relaxation ------------------------------------\n");
5435
5436 nbinvars = SCIPgetNBinVars(scip);
5437 vars = SCIPgetVars(scip);
5438
5439 SCIP_CALL( SCIPallocBufferArray(scip, &bestlb, nnz) );
5440 SCIP_CALL( SCIPallocBufferArray(scip, &bestub, nnz) );
5441 SCIP_CALL( SCIPallocBufferArray(scip, &bestslb, nnz) );
5442 SCIP_CALL( SCIPallocBufferArray(scip, &bestsub, nnz) );
5443 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtype, nnz) );
5444 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtype, nnz) );
5445 SCIP_CALL( SCIPallocBufferArray(scip, &bestslbtype, nnz) );
5446 SCIP_CALL( SCIPallocBufferArray(scip, &bestsubtype, nnz) );
5447 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, nnz) );
5448
5449 /* sort descending to have continuous variables first */
5450 SCIPsortDownInt(rowinds, nnz);
5451
5452 /* array to store whether a binary variable is in the row (-1) or has been used (1) due to variable bound usage */
5453 SCIP_CALL( SCIPallocCleanBufferArray(scip, &binvarused, nbinvars) );
5454
5455 for( i = nnz - 1; i >= 0 && rowinds[i] < nbinvars; --i )
5456 binvarused[rowinds[i]] = -1;
5457
5458 nnonbinvarsrow = i + 1;
5459 /* determine the bounds to use for transforming the non-binary variables */
5460 for( i = 0; i < nnonbinvarsrow; ++i )
5461 {
5462 SCIP_Bool freevariable;
5463
5464 assert(rowinds[i] >= nbinvars);
5465
5466 SCIP_CALL( determineBoundForSNF(scip, sol, vars, rowcoefs, rowinds, i, binvarused, allowlocal, boundswitch,
5467 bestlb, bestub, bestslb, bestsub, bestlbtype, bestubtype, bestslbtype, bestsubtype, selectedbounds, &freevariable) );
5468
5469 if( freevariable )
5470 {
5471 int j;
5472
5473 /* clear binvarused at indices of binary variables of row */
5474 for( j = nnz - 1; j >= nnonbinvarsrow; --j )
5475 binvarused[rowinds[j]] = 0;
5476
5477 /* clear binvarused at indices of selected variable bounds */
5478 for( j = 0; j < i; ++j )
5479 {
5480 if( selectedbounds[j] == SCIP_BOUNDTYPE_LOWER && bestlbtype[j] >= 0 )
5481 {
5482 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(vars[rowinds[j]]);
5483 binvarused[SCIPvarGetProbindex(vlbvars[bestlbtype[j]])] = 0;
5484 }
5485 else if( selectedbounds[j] == SCIP_BOUNDTYPE_UPPER && bestubtype[j] >= 0 )
5486 {
5487 SCIP_VAR** vubvars = SCIPvarGetVubVars(vars[rowinds[j]]);
5488 binvarused[SCIPvarGetProbindex(vubvars[bestubtype[j]])] = 0;
5489 }
5490 }
5491
5492 /* terminate */
5493 goto TERMINATE;
5494 }
5495 }
5496
5497 *localbdsused = FALSE;
5498 QUAD_ASSIGN_Q(transrhs, rowrhs);
5499 snf->ntransvars = 0;
5500
5501 assert(snf->transvarcoefs != NULL); /* for lint */
5502 assert(snf->transvarvubcoefs != NULL);
5503 assert(snf->transbinvarsolvals != NULL);
5504 assert(snf->transcontvarsolvals != NULL);
5505 assert(snf->aggrconstants != NULL);
5506 assert(snf->aggrcoefscont != NULL);
5507 assert(snf->origcontvars != NULL);
5508 assert(snf->origbinvars != NULL);
5509 assert(snf->aggrcoefsbin != NULL);
5510
5511 /* transform non-binary variables */
5512 for( i = 0; i < nnonbinvarsrow; ++i )
5513 {
5514 SCIP_VAR* var;
5515 SCIP_Real QUAD(rowcoef);
5516 SCIP_Real solval;
5517 int probidx;
5518
5519 probidx = rowinds[i];
5520 var = vars[probidx];
5521 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
5522 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
5523 solval = SCIPgetSolVal(scip, sol, var);
5524
5525 assert(probidx >= nbinvars);
5526
5527 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5528 {
5529 /* use bestlb to define y'_j */
5530
5531 assert(!SCIPisInfinity(scip, bestsub[i]));
5532 assert(!SCIPisInfinity(scip, - bestlb[i]));
5533 assert(bestsubtype[i] == -1 || bestsubtype[i] == -2);
5534 assert(bestlbtype[i] > -3 && bestlbtype[i] < SCIPvarGetNVlbs(var));
5535
5536 /* store for y_j that bestlb is the bound used to define y'_j and that y'_j is the associated real variable
5537 * in the relaxed set
5538 */
5539 snf->origcontvars[snf->ntransvars] = probidx;
5540
5541 if( bestlbtype[i] < 0 )
5542 {
5543 SCIP_Real QUAD(val);
5544 SCIP_Real QUAD(contsolval);
5545 SCIP_Real QUAD(rowcoeftimesbestsub);
5546
5547 /* use simple lower bound in bestlb = l_j <= y_j <= u_j = bestsub to define
5548 * 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
5549 * 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,
5550 * put j into the set
5551 * N2 if a_j > 0
5552 * N1 if a_j < 0
5553 * and update the right hand side of the constraint in the relaxation
5554 * rhs = rhs - a_j u_j
5555 */
5556 SCIPquadprecSumDD(val, bestsub[i], -bestlb[i]);
5557 SCIPquadprecProdQQ(val, val, rowcoef);
5558 SCIPquadprecSumDD(contsolval, solval, -bestsub[i]);
5559 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5560
5561 if( bestlbtype[i] == -2 || bestsubtype[i] == -2 )
5562 *localbdsused = TRUE;
5563
5564 SCIPquadprecProdQD(rowcoeftimesbestsub, rowcoef, bestsub[i]);
5565
5566 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5567 snf->origbinvars[snf->ntransvars] = -1;
5568 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5569
5570 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
5571 {
5572 snf->transvarcoefs[snf->ntransvars] = - 1;
5573 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5574 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5575 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5576
5577 /* aggregation information for y'_j */
5578 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestsub);
5579 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5580 }
5581 else
5582 {
5583 snf->transvarcoefs[snf->ntransvars] = 1;
5584 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5585 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5586 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5587
5588 /* aggregation information for y'_j */
5589 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestsub);
5590 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5591 }
5592 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestsub);
5593
5594 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
5595 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5596 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestsub), QUAD_TO_DBL(rowcoef), bestsub[i], QUAD_TO_DBL(transrhs));
5597 }
5598 else
5599 {
5600 SCIP_Real QUAD(rowcoefbinary);
5601 SCIP_Real varsolvalbinary;
5602 SCIP_Real QUAD(val);
5603 SCIP_Real QUAD(contsolval);
5604 SCIP_Real QUAD(rowcoeftimesvlbconst);
5605 int vlbvarprobidx;
5606
5607 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
5608 SCIP_Real* vlbconsts = SCIPvarGetVlbConstants(var);
5609 SCIP_Real* vlbcoefs = SCIPvarGetVlbCoefs(var);
5610
5611 /* use variable lower bound in bestlb = l~_j x_j + d_j <= y_j <= u_j = bestsub to define
5612 * 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
5613 * 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,
5614 * where c_j is the coefficient of x_j in the row, put j into the set
5615 * N2 if a_j > 0
5616 * N1 if a_j < 0
5617 * and update the right hand side of the constraint in the relaxation
5618 * rhs = rhs - a_j d_j
5619 */
5620
5621 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[i]]);
5622 assert(binvarused[vlbvarprobidx] == 1);
5623 assert(vlbvarprobidx < nbinvars);
5624
5625 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vlbvarprobidx);
5626 varsolvalbinary = SCIPgetSolVal(scip, sol, vlbvars[bestlbtype[i]]);
5627
5628 SCIPquadprecProdQD(val, rowcoef, vlbcoefs[bestlbtype[i]]);
5629 SCIPquadprecSumQQ(val, val, rowcoefbinary);
5630 {
5631 SCIP_Real QUAD(tmp);
5632
5633 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
5634 SCIPquadprecSumDD(contsolval, solval, - vlbconsts[bestlbtype[i]]);
5635 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5636 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
5637 }
5638
5639 SCIPquadprecProdQD(rowcoeftimesvlbconst, rowcoef, vlbconsts[bestlbtype[i]]);
5640
5641 /* clear the binvarpos array, since the variable has been processed */
5642 binvarused[vlbvarprobidx] = 0;
5643
5644 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5645 snf->origbinvars[snf->ntransvars] = vlbvarprobidx;
5646
5647 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
5648 {
5649 snf->transvarcoefs[snf->ntransvars] = - 1;
5650 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5651 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5652 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5653
5654 /* aggregation information for y'_j */
5655 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5656 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5657 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvlbconst);
5658 }
5659 else
5660 {
5661 snf->transvarcoefs[snf->ntransvars] = 1;
5662 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5663 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5664 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5665
5666 /* aggregation information for y'_j */
5667 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
5668 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5669 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvlbconst);
5670 }
5671 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvlbconst);
5672
5673 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5674 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5675 snf->ntransvars, SCIPvarGetName(vlbvars[bestlbtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvlbconst), QUAD_TO_DBL(rowcoef),
5676 vlbconsts[bestlbtype[i]], snf->transrhs );
5677 }
5678 }
5679 else
5680 {
5681 /* use bestub to define y'_j */
5682
5683 assert(!SCIPisInfinity(scip, bestub[i]));
5684 assert(!SCIPisInfinity(scip, - bestslb[i]));
5685 assert(bestslbtype[i] == -1 || bestslbtype[i] == -2);
5686 assert(bestubtype[i] > -3 && bestubtype[i] < SCIPvarGetNVubs(var));
5687
5688 /* store for y_j that y'_j is the associated real variable
5689 * in the relaxed set
5690 */
5691 snf->origcontvars[snf->ntransvars] = probidx;
5692
5693 if( bestubtype[i] < 0 )
5694 {
5695 SCIP_Real QUAD(val);
5696 SCIP_Real QUAD(contsolval);
5697 SCIP_Real QUAD(rowcoeftimesbestslb);
5698
5699 /* use simple upper bound in bestslb = l_j <= y_j <= u_j = bestub to define
5700 * 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
5701 * 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,
5702 * put j into the set
5703 * N1 if a_j > 0
5704 * N2 if a_j < 0
5705 * and update the right hand side of the constraint in the relaxation
5706 * rhs = rhs - a_j l_j
5707 */
5708 SCIPquadprecSumDD(val, bestub[i], - bestslb[i]);
5709 SCIPquadprecProdQQ(val, val, rowcoef);
5710 SCIPquadprecSumDD(contsolval, solval, - bestslb[i]);
5711 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5712
5713 if( bestubtype[i] == -2 || bestslbtype[i] == -2 )
5714 *localbdsused = TRUE;
5715
5716 SCIPquadprecProdQD(rowcoeftimesbestslb, rowcoef, bestslb[i]);
5717
5718 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5719 snf->origbinvars[snf->ntransvars] = -1;
5720 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5721
5722 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
5723 {
5724 snf->transvarcoefs[snf->ntransvars] = 1;
5725 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5726 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5727 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5728
5729 /* aggregation information for y'_j */
5730 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5731 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestslb);
5732 }
5733 else
5734 {
5735 snf->transvarcoefs[snf->ntransvars] = - 1;
5736 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5737 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5738 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5739
5740 /* aggregation information for y'_j */
5741 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5742 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestslb);
5743 }
5744 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestslb);
5745
5746 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., Y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
5747 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5748 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestslb), QUAD_TO_DBL(rowcoef), bestslb[i], QUAD_TO_DBL(transrhs));
5749 }
5750 else
5751 {
5752 SCIP_Real QUAD(rowcoefbinary);
5753 SCIP_Real varsolvalbinary;
5754 SCIP_Real QUAD(val);
5755 SCIP_Real QUAD(contsolval);
5756 SCIP_Real QUAD(rowcoeftimesvubconst);
5757 int vubvarprobidx;
5758
5759 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
5760 SCIP_Real* vubconsts = SCIPvarGetVubConstants(var);
5761 SCIP_Real* vubcoefs = SCIPvarGetVubCoefs(var);
5762
5763 /* use variable upper bound in bestslb = l_j <= y_j <= u~_j x_j + d_j = bestub to define
5764 * 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
5765 * 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,
5766 * where c_j is the coefficient of x_j in the row, put j into the set
5767 * N1 if a_j > 0
5768 * N2 if a_j < 0
5769 * and update the right hand side of the constraint in the relaxation
5770 * rhs = rhs - a_j d_j
5771 */
5772
5773 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[i]]);
5774 assert(binvarused[vubvarprobidx] == 1);
5775 assert(vubvarprobidx < nbinvars);
5776
5777 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vubvarprobidx);
5778 varsolvalbinary = SCIPgetSolVal(scip, sol, vubvars[bestubtype[i]]);
5779
5780 /* clear the binvarpos array, since the variable has been processed */
5781 binvarused[vubvarprobidx] = 0;
5782
5783 SCIPquadprecProdQD(val, rowcoef, vubcoefs[bestubtype[i]]);
5784 SCIPquadprecSumQQ(val, val, rowcoefbinary);
5785 {
5786 SCIP_Real QUAD(tmp);
5787 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
5788 SCIPquadprecSumDD(contsolval, solval, - vubconsts[bestubtype[i]]);
5789 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5790 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
5791 }
5792
5793 SCIPquadprecProdQD(rowcoeftimesvubconst, rowcoef, vubconsts[bestubtype[i]]);
5794 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5795 snf->origbinvars[snf->ntransvars] = vubvarprobidx;
5796
5797 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
5798 {
5799 snf->transvarcoefs[snf->ntransvars] = 1;
5800 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5801 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5802 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5803
5804 /* aggregation information for y'_j */
5805 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
5806 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5807 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvubconst);
5808 }
5809 else
5810 {
5811 snf->transvarcoefs[snf->ntransvars] = - 1;
5812 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5813 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5814 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5815
5816 /* aggregation information for y'_j */
5817 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5818 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5819 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvubconst);
5820 }
5821 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvubconst);
5822
5823 /* store for x_j that y'_j is the associated real variable in the 0-1 single node flow relaxation */
5824
5825 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5826 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5827 snf->ntransvars, SCIPvarGetName(vubvars[bestubtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvubconst), QUAD_TO_DBL(rowcoef),
5828 vubconsts[bestubtype[i]], QUAD_TO_DBL(transrhs));
5829 }
5830 }
5831
5832 /* make sure the coefficient is not negative due to small numerical rounding errors */
5833 assert(snf->transvarvubcoefs[snf->ntransvars] > -QUAD_EPSILON);
5834 snf->transvarvubcoefs[snf->ntransvars] = MAX(snf->transvarvubcoefs[snf->ntransvars], 0.0);
5835
5836 ++snf->ntransvars;
5837 }
5838
5839 snf->transrhs = QUAD_TO_DBL(transrhs);
5840
5841 /* transform remaining binary variables of row */
5842 for( i = nnonbinvarsrow; i < nnz; ++i )
5843 {
5844 SCIP_VAR* var;
5845 SCIP_Real QUAD(rowcoef);
5846 int probidx;
5847 SCIP_Real val;
5848 SCIP_Real contsolval;
5849 SCIP_Real varsolval;
5850
5851 probidx = rowinds[i];
5852 /* variable should be binary */
5853 assert(probidx < nbinvars);
5854
5855 /* binary variable was processed together with a non-binary variable */
5856 if( binvarused[probidx] == 0 )
5857 continue;
5858
5859 /* binary variable was not processed yet, so the binvarused value sould be -1 */
5860 assert(binvarused[probidx] == -1);
5861
5862 /* set binvarused to zero since it has been processed */
5863 binvarused[probidx] = 0;
5864
5865 var = vars[probidx];
5866 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
5867 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
5868
5869 varsolval = SCIPgetSolVal(scip, sol, var);
5870 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g, %g]>:\n", i, QUAD_TO_DBL(rowcoef), SCIPvarGetName(var), probidx, varsolval,
5872
5873 /* define
5874 * y'_j = c_j x_j with 0 <= y'_j <= c_j x_j if c_j > 0
5875 * y'_j = - c_j x_j with 0 <= y'_j <= - c_j x_j if c_j < 0,
5876 * where c_j is the coefficient of x_j in the row and put j into the set
5877 * N1 if c_j > 0
5878 * N2 if c_j < 0.
5879 */
5880 val = QUAD_TO_DBL(rowcoef);
5881 contsolval = QUAD_TO_DBL(rowcoef) * varsolval;
5882
5883 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5884 snf->origbinvars[snf->ntransvars] = probidx;
5885 snf->origcontvars[snf->ntransvars] = -1;
5886 snf->aggrcoefscont[snf->ntransvars] = 0.0;
5887 snf->aggrconstants[snf->ntransvars] = 0.0;
5888
5889 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
5890 {
5891 snf->transvarcoefs[snf->ntransvars] = 1;
5892 snf->transvarvubcoefs[snf->ntransvars] = val;
5893 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
5894 snf->transcontvarsolvals[snf->ntransvars] = contsolval;
5895
5896 /* aggregation information for y'_j */
5897 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5898 }
5899 else
5900 {
5901 snf->transvarcoefs[snf->ntransvars] = - 1;
5902 snf->transvarvubcoefs[snf->ntransvars] = - val;
5903 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
5904 snf->transcontvarsolvals[snf->ntransvars] = - contsolval;
5905
5906 /* aggregation information for y'_j */
5907 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5908 }
5909
5910 assert(snf->transvarcoefs[snf->ntransvars] == 1 || snf->transvarcoefs[snf->ntransvars] == - 1 );
5911 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[snf->ntransvars], 0.0)
5912 && SCIPisFeasLE(scip, snf->transbinvarsolvals[snf->ntransvars], 1.0));
5913 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[snf->ntransvars], 0.0)
5915
5916 SCIPdebugMsg(scip, " --> ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s))\n", snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars,
5917 snf->transvarvubcoefs[snf->ntransvars], snf->ntransvars, SCIPvarGetName(var) );
5918
5919 /* updates number of variables in transformed problem */
5920 snf->ntransvars++;
5921 }
5922
5923 /* construction was successful */
5924 *success = TRUE;
5925
5926#ifdef SCIP_DEBUG
5927 SCIPdebugMsg(scip, "constraint in constructed 0-1 single node flow relaxation: ");
5928 for( i = 0; i < snf->ntransvars; i++ )
5929 {
5930 SCIPdebugMsgPrint(scip, "%s y'_%d ", snf->transvarcoefs[i] == 1 ? "+" : "-", i);
5931 }
5932 SCIPdebugMsgPrint(scip, "<= %g\n", snf->transrhs);
5933#endif
5934
5935 TERMINATE:
5936
5937 SCIPfreeCleanBufferArray(scip, &binvarused);
5938 SCIPfreeBufferArray(scip, &selectedbounds);
5939 SCIPfreeBufferArray(scip, &bestsubtype);
5940 SCIPfreeBufferArray(scip, &bestslbtype);
5941 SCIPfreeBufferArray(scip, &bestubtype);
5942 SCIPfreeBufferArray(scip, &bestlbtype);
5943 SCIPfreeBufferArray(scip, &bestsub);
5944 SCIPfreeBufferArray(scip, &bestslb);
5945 SCIPfreeBufferArray(scip, &bestub);
5946 SCIPfreeBufferArray(scip, &bestlb);
5947
5948 return SCIP_OKAY;
5949}
5950
5951/** allocate buffer arrays for storing the single-node-flow relaxation */
5952static
5954 SCIP* scip, /**< SCIP data structure */
5955 SNF_RELAXATION* snf, /**< pointer to snf relaxation to be destroyed */
5956 int nvars /**< number of active problem variables */
5957 )
5958{
5968
5969 return SCIP_OKAY;
5970}
5971
5972/** free buffer arrays for storing the single-node-flow relaxation */
5973static
5975 SCIP* scip, /**< SCIP data structure */
5976 SNF_RELAXATION* snf /**< pointer to snf relaxation to be destroyed */
5977 )
5978{
5988}
5989
5990/** solve knapsack problem in maximization form with "<" constraint approximately by greedy; if needed, one can provide
5991 * arrays to store all selected items and all not selected items
5992 */
5993static
5995 SCIP* scip, /**< SCIP data structure */
5996 int nitems, /**< number of available items */
5997 SCIP_Real* weights, /**< item weights */
5998 SCIP_Real* profits, /**< item profits */
5999 SCIP_Real capacity, /**< capacity of knapsack */
6000 int* items, /**< item numbers */
6001 int* solitems, /**< array to store items in solution, or NULL */
6002 int* nonsolitems, /**< array to store items not in solution, or NULL */
6003 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
6004 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
6005 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
6006 )
6007{
6008 SCIP_Real* tempsort;
6009 SCIP_Real solitemsweight;
6010 SCIP_Real mediancapacity;
6011 int j;
6012 int i;
6013 int criticalitem;
6014
6015 assert(weights != NULL);
6016 assert(profits != NULL);
6017 assert(SCIPisFeasGE(scip, capacity, 0.0));
6018 assert(!SCIPisInfinity(scip, capacity));
6019 assert(items != NULL);
6020 assert(nitems >= 0);
6021
6022 if( solitems != NULL )
6023 {
6024 *nsolitems = 0;
6025 *nnonsolitems = 0;
6026 }
6027 if( solval != NULL )
6028 *solval = 0.0;
6029
6030 /* allocate memory for temporary array used for sorting; array should contain profits divided by corresponding weights (p_1 / w_1 ... p_n / w_n )*/
6031 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
6032
6033 /* initialize temporary array */
6034 for( i = nitems - 1; i >= 0; --i )
6035 tempsort[i] = profits[i] / weights[i];
6036
6037 /* decrease capacity slightly to make it tighter than the original capacity */
6038 mediancapacity = capacity * (1 - SCIPfeastol(scip));
6039
6040 /* rearrange items around */
6041 SCIPselectWeightedDownRealRealInt(tempsort, profits, items, weights, mediancapacity, nitems, &criticalitem);
6042
6043 /* free temporary array */
6044 SCIPfreeBufferArray(scip, &tempsort);
6045
6046 /* select items as long as they fit into the knapsack */
6047 solitemsweight = 0.0;
6048 for( j = 0; j < nitems && SCIPisFeasLT(scip, solitemsweight + weights[j], capacity); j++ )
6049 {
6050 if( solitems != NULL )
6051 {
6052 solitems[*nsolitems] = items[j];
6053 (*nsolitems)++;
6054 }
6055 if( solval != NULL )
6056 (*solval) += profits[j];
6057 solitemsweight += weights[j];
6058 }
6059
6060 /* continue to put items into the knapsack if they entirely fit */
6061 for( ; j < nitems; j++ )
6062 {
6063 if( SCIPisFeasLT(scip, solitemsweight + weights[j], capacity) )
6064 {
6065 if( solitems != NULL )
6066 {
6067 solitems[*nsolitems] = items[j];
6068 (*nsolitems)++;
6069 }
6070 if( solval != NULL )
6071 (*solval) += profits[j];
6072 solitemsweight += weights[j];
6073 }
6074 else if( solitems != NULL )
6075 {
6076 nonsolitems[*nnonsolitems] = items[j];
6077 (*nnonsolitems)++;
6078 }
6079 }
6080
6081 return SCIP_OKAY;
6082}
6083
6084
6085/** build the flow cover which corresponds to the given exact or approximate solution of KP^SNF; given unfinished
6086 * flow cover contains variables which have been fixed in advance
6087 */
6088static
6090 SCIP* scip, /**< SCIP data structure */
6091 int* coefs, /**< coefficient of all real variables in N1&N2 */
6092 SCIP_Real* vubcoefs, /**< coefficient in vub of all real variables in N1&N2 */
6093 SCIP_Real rhs, /**< right hand side of 0-1 single node flow constraint */
6094 int* solitems, /**< items in knapsack */
6095 int* nonsolitems, /**< items not in knapsack */
6096 int nsolitems, /**< number of items in knapsack */
6097 int nnonsolitems, /**< number of items not in knapsack */
6098 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6099 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6100 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6101 QUAD(SCIP_Real* flowcoverweight), /**< pointer to store weight of flow cover */
6102 SCIP_Real* lambda /**< pointer to store lambda */
6103 )
6104{
6105 int j;
6106 SCIP_Real QUAD(tmp);
6107
6108 assert(scip != NULL);
6109 assert(coefs != NULL);
6110 assert(vubcoefs != NULL);
6111 assert(solitems != NULL);
6112 assert(nonsolitems != NULL);
6113 assert(nsolitems >= 0);
6114 assert(nnonsolitems >= 0);
6115 assert(nflowcovervars != NULL && *nflowcovervars >= 0);
6116 assert(nnonflowcovervars != NULL && *nnonflowcovervars >= 0);
6117 assert(flowcoverstatus != NULL);
6118 assert(QUAD_HI(flowcoverweight) != NULL);
6119 assert(lambda != NULL);
6120
6121 /* get flowcover status for each item */
6122 for( j = 0; j < nsolitems; j++ )
6123 {
6124 /* j in N1 with z°_j = 1 => j in N1\C1 */
6125 if( coefs[solitems[j]] == 1 )
6126 {
6127 flowcoverstatus[solitems[j]] = -1;
6128 (*nnonflowcovervars)++;
6129 }
6130 /* j in N2 with z_j = 1 => j in C2 */
6131 else
6132 {
6133 assert(coefs[solitems[j]] == -1);
6134 flowcoverstatus[solitems[j]] = 1;
6135 (*nflowcovervars)++;
6136 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, -vubcoefs[solitems[j]]);
6137 }
6138 }
6139 for( j = 0; j < nnonsolitems; j++ )
6140 {
6141 /* j in N1 with z°_j = 0 => j in C1 */
6142 if( coefs[nonsolitems[j]] == 1 )
6143 {
6144 flowcoverstatus[nonsolitems[j]] = 1;
6145 (*nflowcovervars)++;
6146 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, vubcoefs[nonsolitems[j]]);
6147 }
6148 /* j in N2 with z_j = 0 => j in N2\C2 */
6149 else
6150 {
6151 assert(coefs[nonsolitems[j]] == -1);
6152 flowcoverstatus[nonsolitems[j]] = -1;
6153 (*nnonflowcovervars)++;
6154 }
6155 }
6156
6157 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6158 SCIPquadprecSumQD(tmp, *flowcoverweight, -rhs);
6159 *lambda = QUAD_TO_DBL(tmp);
6160}
6161
6162#ifndef NO_EXACT_KNAPSACK
6163
6164/** checks, whether the given scalar scales the given value to an integral number with error in the given bounds */
6165static
6167 SCIP_Real val, /**< value that should be scaled to an integral value */
6168 SCIP_Real scalar, /**< scalar that should be tried */
6169 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
6170 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
6171 )
6172{
6173 SCIP_Real sval;
6174 SCIP_Real downval;
6175 SCIP_Real upval;
6176
6177 assert(mindelta <= 0.0);
6178 assert(maxdelta >= 0.0);
6179
6180 sval = val * scalar;
6181 downval = floor(sval);
6182 upval = ceil(sval);
6183
6184 return (SCIPrelDiff(sval, downval) <= maxdelta || SCIPrelDiff(sval, upval) >= mindelta);
6185}
6186
6187/** get integral number with error in the bounds which corresponds to given value scaled by a given scalar;
6188 * should be used in connection with isIntegralScalar()
6189 */
6190static
6191SCIP_Longint getIntegralVal(
6192 SCIP_Real val, /**< value that should be scaled to an integral value */
6193 SCIP_Real scalar, /**< scalar that should be tried */
6194 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
6195 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
6196 )
6197{
6198 SCIP_Real sval;
6199 SCIP_Real upval;
6200 SCIP_Longint intval;
6201
6202 assert(mindelta <= 0.0);
6203 assert(maxdelta >= 0.0);
6204
6205 sval = val * scalar;
6206 upval = ceil(sval);
6207
6208 if( SCIPrelDiff(sval, upval) >= mindelta )
6209 intval = (SCIP_Longint) upval;
6210 else
6211 intval = (SCIP_Longint) (floor(sval));
6212
6213 return intval;
6214}
6215
6216/** get a flow cover (C1, C2) for a given 0-1 single node flow set
6217 * {(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},
6218 * 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
6219 */
6220static
6222 SCIP* scip, /**< SCIP data structure */
6223 SNF_RELAXATION* snf, /**< the single node flow relaxation */
6224 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6225 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6226 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6227 SCIP_Real* lambda, /**< pointer to store lambda */
6228 SCIP_Bool* found /**< pointer to store whether a cover was found */
6229 )
6230{
6231 SCIP_Real* transprofitsint;
6232 SCIP_Real* transprofitsreal;
6233 SCIP_Real* transweightsreal;
6234 SCIP_Longint* transweightsint;
6235 int* items;
6236 int* itemsint;
6237 int* nonsolitems;
6238 int* solitems;
6239 SCIP_Real QUAD(flowcoverweight);
6240 SCIP_Real QUAD(flowcoverweightafterfix);
6241 SCIP_Real n1itemsweight;
6242 SCIP_Real n2itemsminweight;
6243 SCIP_Real scalar;
6244 SCIP_Real transcapacityreal;
6245#if !defined(NDEBUG) || defined(SCIP_DEBUG)
6246 SCIP_Bool kpexact;
6247#endif
6248 SCIP_Bool scalesuccess;
6249 SCIP_Bool transweightsrealintegral;
6250 SCIP_Longint transcapacityint;
6251 int nflowcovervarsafterfix;
6252 int nitems;
6253 int nn1items;
6254 int nnonflowcovervarsafterfix;
6255 int nnonsolitems;
6256 int nsolitems;
6257 int j;
6258
6259 assert(scip != NULL);
6260 assert(snf->transvarcoefs != NULL);
6261 assert(snf->transbinvarsolvals != NULL);
6262 assert(snf->transvarvubcoefs != NULL);
6263 assert(snf->ntransvars > 0);
6264 assert(nflowcovervars != NULL);
6265 assert(nnonflowcovervars != NULL);
6266 assert(flowcoverstatus != NULL);
6267 assert(lambda != NULL);
6268 assert(found != NULL);
6269
6270 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
6271
6272 /* get data structures */
6274 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
6275 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
6276 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsint, snf->ntransvars) );
6277 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
6278 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
6279 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
6280 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
6281
6282 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
6283 *found = FALSE;
6284 *nflowcovervars = 0;
6285 *nnonflowcovervars = 0;
6286
6287 QUAD_ASSIGN(flowcoverweight, 0.0);
6288 nflowcovervarsafterfix = 0;
6289 nnonflowcovervarsafterfix = 0;
6290 QUAD_ASSIGN(flowcoverweightafterfix, 0.0);
6291#if !defined(NDEBUG) || defined(SCIP_DEBUG)
6292 kpexact = FALSE;
6293#endif
6294
6295 /* fix some variables in advance according to the following fixing strategy
6296 * put j into N1\C1, if j in N1 and x*_j = 0,
6297 * put j into C1, if j in N1 and x*_j = 1,
6298 * put j into C2, if j in N2 and x*_j = 1,
6299 * put j into N2\C2, if j in N2 and x*_j = 0
6300 * and get the set of the remaining variables
6301 */
6302 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
6303 nitems = 0;
6304 nn1items = 0;
6305 n1itemsweight = 0.0;
6306 n2itemsminweight = SCIP_REAL_MAX;
6307 for( j = 0; j < snf->ntransvars; j++ )
6308 {
6309 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
6310 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
6311 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
6312
6313 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
6314 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
6315 {
6316 flowcoverstatus[j] = -1;
6317 (*nnonflowcovervars)++;
6318 continue;
6319 }
6320
6321 /* x*_j is fractional */
6323 {
6324 items[nitems] = j;
6325 nitems++;
6326 if( snf->transvarcoefs[j] == 1 )
6327 {
6328 n1itemsweight += snf->transvarvubcoefs[j];
6329 nn1items++;
6330 }
6331 else
6332 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
6333 }
6334 /* j is in N1 and x*_j = 0 */
6335 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
6336 {
6337 flowcoverstatus[j] = -1;
6338 (*nnonflowcovervars)++;
6339 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
6340 }
6341 /* j is in N1 and x*_j = 1 */
6342 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
6343 {
6344 flowcoverstatus[j] = 1;
6345 (*nflowcovervars)++;
6346 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
6347 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
6348 }
6349 /* j is in N2 and x*_j = 1 */
6350 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
6351 {
6352 flowcoverstatus[j] = 1;
6353 (*nflowcovervars)++;
6354 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
6355 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
6356 }
6357 /* j is in N2 and x*_j = 0 */
6358 else
6359 {
6360 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
6361 flowcoverstatus[j] = -1;
6362 (*nnonflowcovervars)++;
6363 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
6364 }
6365 }
6366 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
6367 assert(nn1items >= 0);
6368
6369 /* to find a flow cover, transform the following knapsack problem
6370 *
6371 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
6372 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
6373 * z_j in {0,1} for all j in N1 & N2
6374 *
6375 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6376 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
6377 *
6378 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6379 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
6380 * z°_j in {0,1} for all j in N1
6381 * z_j in {0,1} for all j in N2,
6382 * and solve it approximately under consideration of the fixing,
6383 * or
6384 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6385 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
6386 * and multiplying the constraint by a suitable scalar C
6387 *
6388 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6389 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
6390 * z°_j in {0,1} for all j in N1
6391 * z_j in {0,1} for all j in N2,
6392 * where
6393 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
6394 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
6395 * and solve it exactly under consideration of the fixing.
6396 */
6397 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
6398
6399 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
6400 transweightsrealintegral = TRUE;
6401 for( j = 0; j < nitems; j++ )
6402 {
6403 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
6404
6405 if( !isIntegralScalar(transweightsreal[j], 1.0, -MINDELTA, MAXDELTA) )
6406 transweightsrealintegral = FALSE;
6407
6408 if( snf->transvarcoefs[items[j]] == 1 )
6409 {
6410 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
6411 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6412 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6413 }
6414 else
6415 {
6416 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
6417 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6418 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6419 }
6420 }
6421 /* get capacity of knapsack constraint in KP^SNF_rat */
6422 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight;
6423 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
6424 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
6425
6426 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
6427 * is less than or equal to zero
6428 */
6429 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
6430 {
6431 assert(!(*found));
6432 goto TERMINATE;
6433 }
6434
6435 /* KP^SNF_rat has been solved by fixing some variables in advance */
6436 assert(nitems >= 0);
6437 if( nitems == 0)
6438 {
6439 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6440 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
6441 *lambda = QUAD_TO_DBL(flowcoverweight);
6442 *found = TRUE;
6443 goto TERMINATE;
6444 }
6445
6446 /* Use the following strategy
6447 * solve KP^SNF_int exactly, if a suitable factor C is found and (nitems*capacity) <= MAXDYNPROGSPACE,
6448 * solve KP^SNF_rat approximately, otherwise
6449 */
6450
6451 /* find a scaling factor C */
6452 if( transweightsrealintegral )
6453 {
6454 /* weights are already integral */
6455 scalar = 1.0;
6456 scalesuccess = TRUE;
6457 }
6458 else
6459 {
6460 scalesuccess = FALSE;
6461 SCIP_CALL( SCIPcalcIntegralScalar(transweightsreal, nitems, -MINDELTA, MAXDELTA, MAXDNOM, MAXSCALE, &scalar,
6462 &scalesuccess) );
6463 }
6464
6465 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
6466 nsolitems = -1;
6467 nnonsolitems = -1;
6468
6469 /* suitable factor C was found*/
6470 if( scalesuccess )
6471 {
6472 SCIP_Real tmp1;
6473 SCIP_Real tmp2;
6474
6475 /* transform KP^SNF to KP^SNF_int */
6476 for( j = 0; j < nitems; ++j )
6477 {
6478 transweightsint[j] = getIntegralVal(transweightsreal[j], scalar, -MINDELTA, MAXDELTA);
6479 transprofitsint[j] = transprofitsreal[j];
6480 itemsint[j] = items[j];
6481 }
6482 if( isIntegralScalar(transcapacityreal, scalar, -MINDELTA, MAXDELTA) )
6483 {
6484 transcapacityint = getIntegralVal(transcapacityreal, scalar, -MINDELTA, MAXDELTA);
6485 transcapacityint -= 1;
6486 }
6487 else
6488 transcapacityint = (SCIP_Longint) (transcapacityreal * scalar);
6489 nflowcovervarsafterfix = *nflowcovervars;
6490 nnonflowcovervarsafterfix = *nnonflowcovervars;
6491 QUAD_ASSIGN_Q(flowcoverweightafterfix, flowcoverweight);
6492
6493 tmp1 = (SCIP_Real) (nitems + 1);
6494 tmp2 = (SCIP_Real) ((transcapacityint) + 1);
6495 if( transcapacityint * nitems <= MAXDYNPROGSPACE && tmp1 * tmp2 <= INT_MAX / 8.0)
6496 {
6497 SCIP_Bool success;
6498
6499 /* solve KP^SNF_int by dynamic programming */
6500 SCIP_CALL(SCIPsolveKnapsackExactly(scip, nitems, transweightsint, transprofitsint, transcapacityint,
6501 itemsint, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL, &success));
6502
6503 if( !success )
6504 {
6505 /* solve KP^SNF_rat approximately */
6506 SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal,
6507 transcapacityreal, items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6508 }
6509#if !defined(NDEBUG) || defined(SCIP_DEBUG)
6510 else
6511 kpexact = TRUE;
6512#endif
6513 }
6514 else
6515 {
6516 /* solve KP^SNF_rat approximately */
6517 SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6518 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6519 assert(!kpexact);
6520 }
6521 }
6522 else
6523 {
6524 /* solve KP^SNF_rat approximately */
6525 SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6526 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6527 assert(!kpexact);
6528 }
6529
6530 assert(nsolitems != -1);
6531 assert(nnonsolitems != -1);
6532
6533 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
6534 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
6535 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6536 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
6537 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6538
6539 /* if the found structure is not a flow cover, because of scaling, solve KP^SNF_rat approximately */
6540 if( SCIPisFeasLE(scip, *lambda, 0.0) )
6541 {
6542 assert(kpexact);
6543
6544 /* solve KP^SNF_rat approximately */
6545 SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6546 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6547#ifdef SCIP_DEBUG /* this time only for SCIP_DEBUG, because only then, the variable is used again */
6548 kpexact = FALSE;
6549#endif
6550
6551 /* build the flow cover from the solution of KP^SNF_rat and the fixing */
6552 *nflowcovervars = nflowcovervarsafterfix;
6553 *nnonflowcovervars = nnonflowcovervarsafterfix;
6554 QUAD_ASSIGN_Q(flowcoverweight, flowcoverweightafterfix);
6555
6556 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
6557 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6558 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
6559 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6560 }
6561 *found = SCIPisFeasGT(scip, *lambda, 0.0);
6562
6563 TERMINATE:
6564 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
6565#ifdef SCIP_DEBUG
6566 if( *found )
6567 {
6568 SCIPdebugMsg(scip, "2. %s solution:\n", kpexact ? "exact" : "approximate");
6569 for( j = 0; j < snf->ntransvars; j++ )
6570 {
6571 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
6572 {
6573 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6574 }
6575 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
6576 {
6577 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6578 }
6579 }
6580 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
6581 }
6582#endif
6583
6584 /* free data structures */
6585 SCIPfreeBufferArray(scip, &nonsolitems);
6586 SCIPfreeBufferArray(scip, &solitems);
6587 SCIPfreeBufferArray(scip, &transweightsint);
6588 SCIPfreeBufferArray(scip, &transweightsreal);
6589 SCIPfreeBufferArray(scip, &transprofitsint);
6590 SCIPfreeBufferArray(scip, &transprofitsreal);
6591 SCIPfreeBufferArray(scip, &itemsint);
6592 SCIPfreeBufferArray(scip, &items);
6593
6594 return SCIP_OKAY;
6595}
6596
6597#else
6598
6599/** get a flow cover \f$(C1, C2)\f$ for a given 0-1 single node flow set
6600 * \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$,
6601 * i.e., get sets \f$ C1 \subset N1 \f$ and \f$ C2 \subset N2 \f$ with
6602 * \f$ \sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda \f$ and \f$ lambda > 0 \f$
6603 */
6604static
6606 SCIP* scip, /**< SCIP data structure */
6607 SNF_RELAXATION* snf, /**< the 0-1 single node flow relaxation */
6608 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6609 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6610 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6611 SCIP_Real* lambda, /**< pointer to store lambda */
6612 SCIP_Bool* found /**< pointer to store whether a cover was found */
6613 )
6614{
6615 SCIP_Real* transprofitsreal;
6616 SCIP_Real* transweightsreal;
6617 SCIP_Longint* transweightsint;
6618 int* items;
6619 int* itemsint;
6620 int* nonsolitems;
6621 int* solitems;
6622 SCIP_Real QUAD(flowcoverweight);
6623 SCIP_Real n1itemsweight;
6624 SCIP_Real n2itemsminweight;
6625 SCIP_Real transcapacityreal;
6626 int nitems;
6627#ifndef NDEBUG
6628 int nn1items = 0;
6629#endif
6630 int nnonsolitems;
6631 int nsolitems;
6632 int j;
6633
6634 assert(scip != NULL);
6635 assert(snf->transvarcoefs != NULL);
6636 assert(snf->transbinvarsolvals != NULL);
6637 assert(snf->transvarvubcoefs != NULL);
6638 assert(snf->ntransvars > 0);
6639 assert(nflowcovervars != NULL);
6640 assert(nnonflowcovervars != NULL);
6641 assert(flowcoverstatus != NULL);
6642 assert(lambda != NULL);
6643 assert(found != NULL);
6644
6645 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
6646
6647 /* get data structures */
6649 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
6650 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
6651 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
6652 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
6653 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
6654 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
6655
6656 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
6657 *found = FALSE;
6658 *nflowcovervars = 0;
6659 *nnonflowcovervars = 0;
6660
6661 QUAD_ASSIGN(flowcoverweight, 0.0);
6662
6663 /* fix some variables in advance according to the following fixing strategy
6664 * put j into N1\C1, if j in N1 and x*_j = 0,
6665 * put j into C1, if j in N1 and x*_j = 1,
6666 * put j into C2, if j in N2 and x*_j = 1,
6667 * put j into N2\C2, if j in N2 and x*_j = 0
6668 * and get the set of the remaining variables
6669 */
6670 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
6671 nitems = 0;
6672 n1itemsweight = 0.0;
6673 n2itemsminweight = SCIP_REAL_MAX;
6674 for( j = 0; j < snf->ntransvars; j++ )
6675 {
6676 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
6677 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
6678 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
6679
6680 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
6681 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
6682 {
6683 flowcoverstatus[j] = -1;
6684 (*nnonflowcovervars)++;
6685 continue;
6686 }
6687
6688 /* x*_j is fractional */
6690 {
6691 items[nitems] = j;
6692 nitems++;
6693 if( snf->transvarcoefs[j] == 1 )
6694 {
6695 n1itemsweight += snf->transvarvubcoefs[j];
6696#ifndef NDEBUG
6697 nn1items++;
6698#endif
6699 }
6700 else
6701 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
6702 }
6703 /* j is in N1 and x*_j = 0 */
6704 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
6705 {
6706 flowcoverstatus[j] = -1;
6707 (*nnonflowcovervars)++;
6708 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
6709 }
6710 /* j is in N1 and x*_j = 1 */
6711 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
6712 {
6713 flowcoverstatus[j] = 1;
6714 (*nflowcovervars)++;
6715 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
6716 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
6717 }
6718 /* j is in N2 and x*_j = 1 */
6719 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
6720 {
6721 flowcoverstatus[j] = 1;
6722 (*nflowcovervars)++;
6723 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
6724 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
6725 }
6726 /* j is in N2 and x*_j = 0 */
6727 else
6728 {
6729 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
6730 flowcoverstatus[j] = -1;
6731 (*nnonflowcovervars)++;
6732 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
6733 }
6734 }
6735 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
6736 assert(nn1items >= 0);
6737
6738 /* to find a flow cover, transform the following knapsack problem
6739 *
6740 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
6741 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
6742 * z_j in {0,1} for all j in N1 & N2
6743 *
6744 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6745 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
6746 *
6747 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6748 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
6749 * z°_j in {0,1} for all j in N1
6750 * z_j in {0,1} for all j in N2,
6751 * and solve it approximately under consideration of the fixing,
6752 * or
6753 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6754 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
6755 * and multiplying the constraint by a suitable scalar C
6756 *
6757 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6758 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
6759 * z°_j in {0,1} for all j in N1
6760 * z_j in {0,1} for all j in N2,
6761 * where
6762 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
6763 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
6764 * and solve it exactly under consideration of the fixing.
6765 */
6766 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
6767
6768 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
6769 for( j = 0; j < nitems; j++ )
6770 {
6771 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
6772
6773 if( snf->transvarcoefs[items[j]] == 1 )
6774 {
6775 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
6776 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6777 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6778 }
6779 else
6780 {
6781 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
6782 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6783 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6784 }
6785 }
6786 /* get capacity of knapsack constraint in KP^SNF_rat */
6787 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight; /*lint !e644*/
6788 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
6789 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
6790
6791 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
6792 * is less than or equal to zero
6793 */
6794 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
6795 {
6796 assert(!(*found));
6797 goto TERMINATE;
6798 }
6799
6800 /* KP^SNF_rat has been solved by fixing some variables in advance */
6801 assert(nitems >= 0);
6802 if( nitems == 0 )
6803 {
6804 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6805 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
6806 *lambda = QUAD_TO_DBL(flowcoverweight);
6807 *found = TRUE;
6808 goto TERMINATE;
6809 }
6810
6811 /* Solve the KP^SNF_rat approximately */
6812
6813 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
6814 nsolitems = -1;
6815 nnonsolitems = -1;
6816
6817 /* suitable factor C was found*/
6818 /* solve KP^SNF_rat approximately */
6819 SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6820 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6821
6822 assert(nsolitems != -1);
6823 assert(nnonsolitems != -1);
6824
6825 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
6826 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
6827 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6828 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
6829 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6830
6831 *found = SCIPisFeasGT(scip, *lambda, 0.0);
6832
6833 TERMINATE:
6834 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
6835#ifdef SCIP_DEBUG
6836 if( *found )
6837 {
6838 SCIPdebugMsg(scip, "2. approximate solution:\n");
6839 for( j = 0; j < snf->ntransvars; j++ )
6840 {
6841 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
6842 {
6843 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6844 }
6845 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
6846 {
6847 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6848 }
6849 }
6850 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
6851 }
6852#endif
6853
6854 /* free data structures */
6855 SCIPfreeBufferArray(scip, &nonsolitems);
6856 SCIPfreeBufferArray(scip, &solitems);
6857 SCIPfreeBufferArray(scip, &transweightsint);
6858 SCIPfreeBufferArray(scip, &transweightsreal);
6859 SCIPfreeBufferArray(scip, &transprofitsreal);
6860 SCIPfreeBufferArray(scip, &itemsint);
6861 SCIPfreeBufferArray(scip, &items);
6862
6863 return SCIP_OKAY;
6864}
6865
6866#endif
6867
6868/** evaluate the super-additive lifting function for the lifted simple generalized flowcover inequalities
6869 * for a given value \f$ x \in \{ u_j \mid j \in C- \} \f$.
6870 */
6871static
6873 SCIP* scip, /**< SCIP data structure */
6874 LIFTINGDATA* liftingdata, /**< lifting data to use */
6875 SCIP_Real x /**< value where to evaluate lifting function */
6876 )
6877{
6878 SCIP_Real QUAD(tmp);
6879 SCIP_Real xpluslambda;
6880 int i;
6881
6882 assert( liftingdata != NULL );
6883
6884 xpluslambda = x + liftingdata->lambda;
6885
6886 i = 0;
6887 while( i < liftingdata->r && SCIPisGT(scip, xpluslambda, liftingdata->M[i+1]) )
6888 ++i;
6889
6890 if( i < liftingdata->t )
6891 {
6892 if( SCIPisLE(scip, liftingdata->M[i], x) )
6893 {
6894 assert(SCIPisLE(scip, xpluslambda, liftingdata->M[i+1]));
6895 return i * liftingdata->lambda;
6896 }
6897
6898 assert(i > 0 && SCIPisLE(scip, liftingdata->M[i], xpluslambda) && x <= liftingdata->M[i]);
6899
6900 /* return x - liftingdata->M[i] + i * liftingdata->lambda */
6901 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
6902 SCIPquadprecSumQD(tmp, tmp, x);
6903 SCIPquadprecSumQD(tmp, tmp, -liftingdata->M[i]);
6904 return QUAD_TO_DBL(tmp);
6905 }
6906
6907 if( i < liftingdata->r )
6908 {
6909 assert(!SCIPisInfinity(scip, liftingdata->mp));
6910
6911 /* p = liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml; */
6912 SCIPquadprecSumDD(tmp, liftingdata->m[i], -liftingdata->mp);
6913 SCIPquadprecSumQD(tmp, tmp, -liftingdata->ml);
6914 SCIPquadprecSumQD(tmp, tmp, liftingdata->lambda);
6915
6916 /* p = MAX(0.0, p); */
6917 if( QUAD_HI(tmp) < 0.0 )
6918 {
6919 QUAD_ASSIGN(tmp, 0.0);
6920 }
6921
6922 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
6923 SCIPquadprecSumQD(tmp, tmp, liftingdata->ml);
6924
6925 if( SCIPisLT(scip, QUAD_TO_DBL(tmp), xpluslambda) )
6926 return i * liftingdata->lambda;
6927
6928 assert(SCIPisFeasLE(scip, liftingdata->M[i], xpluslambda) &&
6929 SCIPisFeasLE(scip, xpluslambda, liftingdata->M[i] + liftingdata->ml +
6930 MAX(0.0, liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml)));
6931
6932 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
6933 SCIPquadprecSumQD(tmp, tmp, x);
6934 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[i]);
6935 return QUAD_TO_DBL(tmp);
6936 }
6937
6938 assert(i == liftingdata->r && SCIPisLE(scip, liftingdata->M[liftingdata->r], xpluslambda));
6939
6940 SCIPquadprecProdDD(tmp, liftingdata->r, liftingdata->lambda);
6941 SCIPquadprecSumQD(tmp, tmp, x);
6942 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[liftingdata->r]);
6943 return QUAD_TO_DBL(tmp);
6944}
6945
6946/** computes
6947 * \f[
6948 * (\alpha_j, \beta_j) =
6949 * \begin{cases}
6950 * (0, 0) &\quad\text{if} M_i \leq u_j \leq M_{i+1} - \lambda \\
6951 * (1, M_i - i \lambda) &\quad\text{if} M_i − \lambda < u_j < M_i \\
6952 * \end{cases}
6953 * \f]
6954 */
6955static
6957 SCIP* scip, /**< SCIP data structure */
6958 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
6959 SCIP_Real vubcoef, /**< vub coefficient to get alpha and beta for */
6960 int* alpha, /**< get alpha coefficient for lifting */
6961 SCIP_Real* beta /**< get beta coefficient for lifting */
6962 )
6963{
6964 SCIP_Real vubcoefpluslambda;
6965 int i;
6966
6967 vubcoefpluslambda = vubcoef + liftingdata->lambda;
6968
6969 i = 0;
6970 while( i < liftingdata->r && SCIPisGT(scip, vubcoefpluslambda, liftingdata->M[i+1]) )
6971 ++i;
6972
6973 if( SCIPisLT(scip, vubcoef, liftingdata->M[i]) )
6974 {
6975 SCIP_Real QUAD(tmp);
6976 assert(liftingdata->M[i] < vubcoefpluslambda);
6977 *alpha = 1;
6978 SCIPquadprecProdDD(tmp, -i, liftingdata->lambda);
6979 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
6980 *beta = QUAD_TO_DBL(tmp);
6981 }
6982 else
6983 {
6984 assert(SCIPisSumLE(scip, liftingdata->M[i], vubcoef));
6985 assert(i == liftingdata->r || SCIPisLE(scip, vubcoefpluslambda, liftingdata->M[i+1]));
6986 *alpha = 0;
6987 *beta = 0.0;
6988 }
6989}
6990
6991/** compute relevant data for performing the sequence independent lifting */
6992static
6994 SCIP* scip, /**< SCIP data structure */
6995 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
6996 int* transvarflowcoverstatus, /**< pointer to store whether non-binary var is in L2 (2) or not (-1 or 1) */
6997 SCIP_Real lambda, /**< lambda */
6998 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
6999 SCIP_Bool* valid /**< is the lifting data valid */
7000 )
7001{
7002 int i;
7003 SCIP_Real QUAD(tmp);
7004 SCIP_Real QUAD(sumN2mC2LE);
7005 SCIP_Real QUAD(sumN2mC2GT);
7006 SCIP_Real QUAD(sumC1LE);
7007 SCIP_Real QUAD(sumC2);
7008
7009#ifndef NDEBUG
7010 /* for debugging */
7011 liftingdata->m = NULL;
7012 liftingdata->M = NULL;
7013 liftingdata->lambda = SCIP_INVALID;
7014 liftingdata->t = 0;
7015 liftingdata->mp = SCIP_INVALID;
7016#endif
7017
7018 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->m, snf->ntransvars) );
7019
7020 liftingdata->r = 0;
7021 QUAD_ASSIGN(sumN2mC2LE, 0.0);
7022 QUAD_ASSIGN(sumC1LE, 0.0);
7023 QUAD_ASSIGN(sumN2mC2GT, 0.0);
7024 QUAD_ASSIGN(sumC2, 0.0);
7025
7026 liftingdata->mp = SCIPinfinity(scip);
7027
7028 *valid = FALSE;
7029
7030 for( i = 0; i < snf->ntransvars; ++i )
7031 {
7032 int s = (snf->transvarcoefs[i] + 1) + (transvarflowcoverstatus[i] + 1)/2;
7033
7034 switch(s)
7035 {
7036 case 0: /* var is in N2 \ C2 */
7037 assert(snf->transvarvubcoefs[i] >= 0.0);
7038 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == -1);
7039
7040 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7041 {
7042 SCIPquadprecSumQD(sumN2mC2GT, sumN2mC2GT, snf->transvarvubcoefs[i]);
7043 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
7044 }
7045 else
7046 {
7047 SCIPquadprecSumQD(sumN2mC2LE, sumN2mC2LE, snf->transvarvubcoefs[i]);
7048 }
7049 break;
7050 case 1: /* var is in C2 */
7051 assert(snf->transvarvubcoefs[i] > 0.0);
7052 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == 1);
7053
7054 SCIPquadprecSumQD(sumC2, sumC2, snf->transvarvubcoefs[i]);
7055 break;
7056 case 3: /* var is in C1 */
7057 assert(snf->transvarcoefs[i] == 1 && transvarflowcoverstatus[i] == 1);
7058 assert(snf->transvarvubcoefs[i] > 0.0);
7059
7060 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7061 {
7062 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
7063 liftingdata->mp = MIN(liftingdata->mp, snf->transvarvubcoefs[i]);
7064 }
7065 else
7066 {
7067 SCIPquadprecSumQD(sumC1LE, sumC1LE, snf->transvarvubcoefs[i]);
7068 }
7069 break;
7070 default:
7071 assert(s == 2);
7072 continue;
7073 }
7074 }
7075
7076 if( SCIPisInfinity(scip, liftingdata->mp) )
7077 {
7078 SCIPfreeBufferArray(scip, &liftingdata->m);
7079 return SCIP_OKAY;
7080 }
7081
7082 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->M, liftingdata->r + 1) );
7083
7084 *valid = TRUE;
7085
7086 SCIPquadprecSumQQ(tmp, sumC1LE, sumN2mC2LE);
7087 liftingdata->ml = MIN(lambda, QUAD_TO_DBL(tmp));
7088 SCIPquadprecSumQD(tmp, sumC2, snf->transrhs);
7089 liftingdata->d1 = QUAD_TO_DBL(tmp);
7090 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2GT);
7091 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2LE);
7092 liftingdata->d2 = QUAD_TO_DBL(tmp);
7093
7094 SCIPsortDownReal(liftingdata->m, liftingdata->r);
7095
7096 /* compute M[i] = sum_{i \in [1,r]} m[i] where m[*] is sorted decreasingly and M[0] = 0 */
7097 QUAD_ASSIGN(tmp, 0.0);
7098 for( i = 0; i < liftingdata->r; ++i)
7099 {
7100 liftingdata->M[i] = QUAD_TO_DBL(tmp);
7101 SCIPquadprecSumQD(tmp, tmp, liftingdata->m[i]);
7102 }
7103
7104 liftingdata->M[liftingdata->r] = QUAD_TO_DBL(tmp);
7105
7106 SCIP_UNUSED( SCIPsortedvecFindDownReal(liftingdata->m, liftingdata->mp, liftingdata->r, &liftingdata->t) );
7107 assert(liftingdata->m[liftingdata->t] == liftingdata->mp || SCIPisInfinity(scip, liftingdata->mp)); /*lint !e777*/
7108
7109 /* compute t largest index sucht that m_t = mp
7110 * note that liftingdata->m[t-1] == mp due to zero based indexing of liftingdata->m
7111 */
7112 ++liftingdata->t;
7113 while( liftingdata->t < liftingdata->r && liftingdata->m[liftingdata->t] == liftingdata->mp ) /*lint !e777*/
7114 ++liftingdata->t;
7115
7116 liftingdata->lambda = lambda;
7117
7118 return SCIP_OKAY;
7119}
7120
7121/** destroy data used for the sequence independent lifting */
7122static
7124 SCIP* scip, /**< SCIP data structure */
7125 LIFTINGDATA* liftingdata /**< pointer to lifting function struct */
7126 )
7127{
7128 SCIPfreeBufferArray(scip, &liftingdata->M);
7129 SCIPfreeBufferArray(scip, &liftingdata->m);
7130}
7131
7132/** store the simple lifted flowcover cut defined by the given data in the given arrays
7133 * the array for storing the cut coefficients must be all zeros
7134 */
7135static
7137 SCIP* scip, /**< SCIP data structure */
7138 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
7139 SCIP_AGGRROW* aggrrow, /**< aggrrow used to construct SNF relaxation */
7140 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
7141 SCIP_Real lambda, /**< lambda */
7142 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7143 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
7144 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7145 int* nnz, /**< number of non-zeros in cut */
7146 SCIP_Bool* success /**< was the cut successfully generated */
7147 )
7148{
7149 SCIP_Real QUAD(rhs);
7150 LIFTINGDATA liftingdata;
7151 int i;
7152
7153 SCIP_CALL( computeLiftingData(scip, snf, flowcoverstatus, lambda, &liftingdata, success) );
7154 if( ! *success )
7155 return SCIP_OKAY;
7156 assert( liftingdata.m != NULL );
7157 assert( liftingdata.M != NULL );
7158 assert( liftingdata.lambda != SCIP_INVALID ); /*lint !e777*/
7159 assert( liftingdata.r >= 0 );
7160 assert( liftingdata.t >= 0 );
7161 assert( liftingdata.mp != SCIP_INVALID ); /*lint !e777*/
7162
7163 QUAD_ASSIGN(rhs, liftingdata.d1);
7164
7165 *nnz = 0;
7166
7167 for( i = 0; i < snf->ntransvars; ++i )
7168 {
7169 int s = (snf->transvarcoefs[i] + 1) + (flowcoverstatus[i] + 1)/2;
7170
7171 switch(s)
7172 {
7173 case 0: /* var is in N2 \ C2 */
7174 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7175 {
7176 /* var is in L- */
7177 if( snf->origbinvars[i] != -1 )
7178 {
7179 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7180 cutinds[*nnz] = snf->origbinvars[i];
7181 cutcoefs[snf->origbinvars[i]] = -lambda;
7182 ++(*nnz);
7183 }
7184 else
7185 {
7186 SCIPquadprecSumQD(rhs, rhs, lambda);
7187 }
7188 }
7189 else
7190 {
7191 /* var is in L-- */
7192 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7193 {
7194 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7195 cutinds[*nnz] = snf->origcontvars[i];
7196 cutcoefs[snf->origcontvars[i]] = -snf->aggrcoefscont[i];
7197 ++(*nnz);
7198 }
7199
7200 if( snf->origbinvars[i] != -1 && snf->aggrcoefsbin[i] != 0.0 )
7201 {
7202 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7203 cutinds[*nnz] = snf->origbinvars[i];
7204 cutcoefs[snf->origbinvars[i]] = -snf->aggrcoefsbin[i];
7205 ++(*nnz);
7206 }
7207
7208 SCIPquadprecSumQD(rhs, rhs, snf->aggrconstants[i]);
7209 }
7210 break;
7211 case 1: /* var is in C2 */
7212 {
7213 assert(snf->transvarvubcoefs[i] > 0.0);
7214 assert(snf->transvarcoefs[i] == -1 && flowcoverstatus[i] == 1);
7215
7216 if( snf->origbinvars[i] != -1 )
7217 {
7218 SCIP_Real liftedbincoef = evaluateLiftingFunction(scip, &liftingdata, snf->transvarvubcoefs[i]);
7219 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7220 if( liftedbincoef != 0.0 )
7221 {
7222 cutinds[*nnz] = snf->origbinvars[i];
7223 cutcoefs[snf->origbinvars[i]] = -liftedbincoef;
7224 ++(*nnz);
7225 SCIPquadprecSumQD(rhs, rhs, -liftedbincoef);
7226 }
7227 }
7228 break;
7229 }
7230 case 2: /* var is in N1 \ C1 */
7231 {
7232 int alpha;
7233 SCIP_Real beta;
7234
7235 assert(snf->transvarcoefs[i] == 1 && flowcoverstatus[i] == -1);
7236
7237 getAlphaAndBeta(scip, &liftingdata, snf->transvarvubcoefs[i], &alpha, &beta);
7238 assert(alpha == 0 || alpha == 1);
7239
7240 if( alpha == 1 )
7241 {
7242 SCIP_Real QUAD(binvarcoef);
7243 assert(beta > 0.0);
7244
7245 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7246 {
7247 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7248 cutinds[*nnz] = snf->origcontvars[i];
7249 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
7250 ++(*nnz);
7251 }
7252
7253 SCIPquadprecSumDD(binvarcoef, snf->aggrcoefsbin[i], -beta);
7254 if( snf->origbinvars[i] != -1 )
7255 {
7256 SCIP_Real tmp;
7257
7258 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7259
7260 tmp = QUAD_TO_DBL(binvarcoef);
7261 if( tmp != 0.0 )
7262 {
7263 cutinds[*nnz] = snf->origbinvars[i];
7264 cutcoefs[snf->origbinvars[i]] = tmp;
7265 ++(*nnz);
7266 }
7267 }
7268 else
7269 {
7270 SCIPquadprecSumQQ(rhs, rhs, -binvarcoef);
7271 }
7272
7273 SCIPquadprecSumQD(rhs, rhs, -snf->aggrconstants[i]);
7274 }
7275 break;
7276 }
7277 case 3: /* var is in C1 */
7278 {
7279 SCIP_Real bincoef = snf->aggrcoefsbin[i];
7280 SCIP_Real constant = snf->aggrconstants[i];
7281
7282 if( snf->origbinvars[i] != -1 && SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7283 {
7284 /* var is in C++ */
7285 SCIP_Real QUAD(tmp);
7286 SCIP_Real QUAD(tmp2);
7287
7288 SCIPquadprecSumDD(tmp, snf->transvarvubcoefs[i], -lambda);
7289
7290 SCIPquadprecSumQD(tmp2, tmp, constant);
7291 constant = QUAD_TO_DBL(tmp2);
7292
7293 SCIPquadprecSumQD(tmp2, tmp, -bincoef);
7294 bincoef = -QUAD_TO_DBL(tmp2);
7295 }
7296
7297 if( snf->origbinvars[i] != -1 && bincoef != 0.0 )
7298 {
7299 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7300 cutinds[*nnz] = snf->origbinvars[i];
7301 cutcoefs[snf->origbinvars[i]] = bincoef;
7302 ++(*nnz);
7303 }
7304
7305 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7306 {
7307 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7308 cutinds[*nnz] = snf->origcontvars[i];
7309 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
7310 ++(*nnz);
7311 }
7312
7313 SCIPquadprecSumQD(rhs, rhs, -constant);
7314 break;
7315 }
7316 default:
7317 SCIPABORT();
7318 }
7319 }
7320
7321 destroyLiftingData(scip, &liftingdata);
7322
7323 {
7324 SCIP_ROW** rows = SCIPgetLPRows(scip);
7325 for( i = 0; i < aggrrow->nrows; ++i )
7326 {
7327 SCIP_ROW* row;
7328 SCIP_Real rowlhs;
7329 SCIP_Real rowrhs;
7330 SCIP_Real slackub;
7331 SCIP_Real slackcoef;
7332
7333 slackcoef = aggrrow->rowweights[i] * aggrrow->slacksign[i];
7334 assert(slackcoef != 0.0);
7335
7336 /* positive slack was implicitly handled in flow cover separation */
7337 if( slackcoef > 0.0 )
7338 continue;
7339
7340 row = rows[aggrrow->rowsinds[i]];
7341
7342 /* add the slack's definition multiplied with its coefficient to the cut */
7343 SCIP_CALL( varVecAddScaledRowCoefs(cutinds, cutcoefs, nnz, row, -aggrrow->rowweights[i]) );
7344
7345 /* retrieve sides of row */
7346 rowlhs = row->lhs - row->constant;
7347 rowrhs = row->rhs - row->constant;
7348
7349 if( row->integral )
7350 {
7351 rowrhs = SCIPfloor(scip, rowrhs);
7352 rowlhs = SCIPceil(scip, rowlhs);
7353 }
7354
7355 slackub = rowrhs - rowlhs;
7356
7357 /* move slack's constant to the right hand side, and add lambda to the right hand side if the
7358 * upper bound of the slack is larger than lambda, since then an artifical binary variable
7359 * for the slack would get coefficient -lambda
7360 */
7361 if( aggrrow->slacksign[i] == +1 )
7362 {
7363 SCIP_Real rhsslack;
7364 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7365 assert(!SCIPisInfinity(scip, row->rhs));
7366
7367 rhsslack = rowrhs - SCIPgetRowMinActivity(scip, row);
7368 slackub = -aggrrow->rowweights[i] * MIN(rhsslack, slackub);
7369
7370 if( SCIPisGE(scip, slackub, lambda) )
7371 SCIPquadprecSumQD(rhs, rhs, lambda);
7372
7373 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowrhs);
7374 }
7375 else
7376 {
7377 SCIP_Real lhsslack;
7378 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7379 assert(!SCIPisInfinity(scip, -row->lhs));
7380
7381 lhsslack = SCIPgetRowMaxActivity(scip, row) - rowlhs;
7382 slackub = aggrrow->rowweights[i] * MIN(lhsslack, slackub);
7383
7384 if( SCIPisGE(scip, slackub, lambda) )
7385 SCIPquadprecSumQD(rhs, rhs, lambda);
7386
7387 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowlhs);
7388 }
7389 }
7390 }
7391
7392 *cutrhs = QUAD_TO_DBL(rhs);
7393
7394 /* relax rhs to zero, if it's very close to 0 */
7395 if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
7396 *cutrhs = 0.0;
7397
7398 return SCIP_OKAY;
7399}
7400
7401/** calculates a lifted simple generalized flow cover cut out of the weighted sum of LP rows given by an aggregation row; the
7402 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
7403 * participate in the cut.
7404 * For further details we refer to:
7405 *
7406 * Gu, Z., Nemhauser, G. L., & Savelsbergh, M. W. (1999). Lifted flow cover inequalities for mixed 0-1 integer programs.
7407 * Mathematical Programming, 85(3), 439-467.
7408 *
7409 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7410 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7411 *
7412 * @pre This method can be called if @p scip is in one of the following stages:
7413 * - \ref SCIP_STAGE_SOLVING
7414 *
7415 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
7416 */
7418 SCIP* scip, /**< SCIP data structure */
7419 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7420 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
7421 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
7422 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7423 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
7424 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
7425 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
7426 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
7427 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
7428 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
7429 int* cutrank, /**< pointer to return rank of generated cut */
7430 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
7431 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
7432 )
7433{
7434 int i;
7435 int nvars;
7436 SCIP_Bool localbdsused;
7437 SNF_RELAXATION snf;
7438 SCIP_Real lambda;
7439 SCIP_Real* tmpcoefs;
7440 int *transvarflowcoverstatus;
7441 int nflowcovervars;
7442 int nnonflowcovervars;
7443
7444 nvars = SCIPgetNVars(scip);
7445
7446 *success = FALSE;
7447
7448 /* get data structures */
7449 SCIP_CALL( SCIPallocBufferArray(scip, &transvarflowcoverstatus, nvars) );
7450 SCIP_CALL( allocSNFRelaxation(scip, &snf, nvars) );
7451
7452 SCIPdebug( printCutQuad(scip, sol, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, FALSE, aggrrow->local) );
7453
7454 SCIP_CALL( constructSNFRelaxation(scip, sol, boundswitch, allowlocal, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, &snf, success, &localbdsused) );
7455
7456 if( ! *success )
7457 {
7458 goto TERMINATE;
7459 }
7460
7461 *cutislocal = aggrrow->local || localbdsused;
7462
7463 /* initialize lambda because gcc issues a stupid warning */
7464 lambda = 0.0;
7465 SCIP_CALL( getFlowCover(scip, &snf, &nflowcovervars, &nnonflowcovervars, transvarflowcoverstatus, &lambda, success) );
7466
7467 if( ! *success )
7468 {
7469 goto TERMINATE;
7470 }
7471
7472 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
7473
7474 SCIP_CALL( generateLiftedFlowCoverCut(scip, &snf, aggrrow, transvarflowcoverstatus, lambda, tmpcoefs, cutrhs, cutinds, cutnnz, success) );
7475 SCIPdebugMsg(scip, "computed flowcover_%lli_%i:\n", SCIPgetNLPs(scip), SCIPgetNCuts(scip));
7476
7477 /* if success is FALSE generateLiftedFlowCoverCut wont have touched the tmpcoefs array so we dont need to clean it then */
7478 if( *success )
7479 {
7480 if( postprocess )
7481 {
7482 SCIP_CALL( postprocessCut(scip, *cutislocal, cutinds, tmpcoefs, cutnnz, cutrhs, success) );
7483 }
7484 else
7485 {
7486 SCIP_Real QUAD(rhs);
7487
7488 QUAD_ASSIGN(rhs, *cutrhs);
7489 *success = ! removeZeros(scip, SCIPsumepsilon(scip), *cutislocal, tmpcoefs, QUAD(&rhs), cutinds, cutnnz);
7490 *cutrhs = QUAD_TO_DBL(rhs);
7491 }
7492
7493 if( *success )
7494 {
7495 /* store cut sparse and calculate efficacy */
7496 for( i = 0; i < *cutnnz; ++i )
7497 {
7498 int j = cutinds[i];
7499 assert(tmpcoefs[j] != 0.0);
7500 cutcoefs[i] = tmpcoefs[j];
7501 tmpcoefs[j] = 0.0;
7502 }
7503
7504 if( cutefficacy != NULL )
7505 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
7506
7507 if( cutrank != NULL )
7508 *cutrank = aggrrow->rank + 1;
7509 }
7510 else
7511 {
7512 /* clean buffer array */
7513 for( i = 0; i < *cutnnz; ++i )
7514 {
7515 int j = cutinds[i];
7516 assert(tmpcoefs[j] != 0.0);
7517 tmpcoefs[j] = 0.0;
7518 }
7519 }
7520 }
7521
7522 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
7523
7524 TERMINATE:
7526 SCIPfreeBufferArray(scip, &transvarflowcoverstatus);
7527
7528 return SCIP_OKAY;
7529}
7530
7531/* =========================================== knapsack cover =========================================== */
7532
7533/** Relax the row to a possibly fractional knapsack row containing no integer or continuous variables
7534 * and only having positive coefficients for binary variables. General integer and continuous variables
7535 * are complemented with variable or simple bounds such that their coefficient becomes positive and then
7536 * it is relaxed to zero.
7537 * All remaining binary variables are complemented with simple upper or lower bounds such that their
7538 * coefficient becomes positive.
7539 */
7540static
7542 SCIP* scip, /**< SCIP data structure */
7543 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7544 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7545 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7546 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
7547 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7548 int* nnz, /**< number of non-zeros in cut */
7549 int* varsign, /**< stores the sign of the transformed variable in summation */
7550 int* boundtype, /**< stores the bound used for transformed variable:
7551 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
7552 SCIP_Bool* localbdsused, /**< pointer to store whether local bounds were used in transformation */
7553 SCIP_Bool* success /**< stores whether the row could successfully be transformed into a knapsack constraint.
7554 * Returns FALSE in case a continuous or general integer variable is unbounded in the
7555 * required direction. */
7556 )
7557{
7558 SCIP_Real* bestbds;
7559 int i;
7560 int aggrrowbinstart;
7561 int firstnonbinvar;
7562 SCIP_VAR** vars;
7563
7564 assert(varsign != NULL);
7565 assert(boundtype != NULL);
7566 assert(success != NULL);
7567 assert(localbdsused != NULL);
7568
7569 *success = FALSE;
7570
7571 /* allocate temporary memory to store best bounds and bound types */
7572 SCIP_CALL( SCIPallocBufferArray(scip, &bestbds, 2*(*nnz)) );
7573
7574 /* start with continuous variables, because using variable bounds can affect the untransformed binary
7575 * variables, and these changes have to be incorporated in the transformation of the binary variables
7576 * (binary variables have the smallest problem indices!)
7577 */
7578 SCIPsortDownInt(cutinds, *nnz);
7579
7580 vars = SCIPgetVars(scip);
7581 firstnonbinvar = SCIPgetNBinVars(scip);
7582
7583 /* determine best bounds for the continuous and general integer variables such that they will have
7584 * a positive coefficient in the transformation */
7585 for( i = 0; i < *nnz && cutinds[i] >= firstnonbinvar; ++i )
7586 {
7587 SCIP_Real QUAD(coef);
7588 int v = cutinds[i];
7589
7590 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7591
7592 if( QUAD_TO_DBL(coef) > 0.0 )
7593 {
7594 SCIP_Real simplebound;
7595
7596 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable
7597 * so that it will have a positive coefficient */
7598 SCIP_CALL( findBestLb(scip, vars[v], sol, 1, allowlocal, bestbds + i, &simplebound, boundtype + i) );
7599
7600 /* cannot transform into knapsack */
7601 if( SCIPisInfinity(scip, -bestbds[i]) )
7602 goto TERMINATE;
7603
7604 varsign[i] = +1;
7605 }
7606 else if( QUAD_TO_DBL(coef) < 0.0 )
7607 {
7608 SCIP_Real simplebound;
7609
7610 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable
7611 * so that it will have a positive coefficient */
7612 SCIP_CALL( findBestUb(scip, vars[v], sol, 1, allowlocal, bestbds + i, &simplebound, boundtype + i) );
7613
7614 /* cannot transform into knapsack */
7615 if( SCIPisInfinity(scip, bestbds[i]) )
7616 goto TERMINATE;
7617
7618 varsign[i] = -1;
7619 }
7620 }
7621
7622 /* remember start of integer variables in the aggrrow */
7623 aggrrowbinstart = i;
7624
7625 /* perform bound substitution for continuous variables */
7626 for( i = 0; i < aggrrowbinstart; ++i )
7627 {
7628 SCIP_Real QUAD(coef);
7629 int v = cutinds[i];
7630
7631 performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestbds[i], v, localbdsused);
7632
7633 /* relax non-binary coefficient to zero after bound substitution */
7634 QUAD_ASSIGN(coef, 0.0);
7635 QUAD_ARRAY_STORE(cutcoefs, v, coef);
7636 }
7637
7638 assert(i == aggrrowbinstart);
7639
7640 /* remove non-binary variables because their coefficients have been set to zero after bound substitution */
7641 if( aggrrowbinstart != 0 )
7642 {
7643 *nnz -= aggrrowbinstart;
7644 BMSmoveMemoryArray(cutinds, cutinds + aggrrowbinstart, *nnz);
7645 }
7646 i = 0;
7647
7648 /* after doing bound substitution of non-binary vars, some coefficients of binary vars might have changed, so here we
7649 * remove the ones that became 0 if any; also, we need that all remaining binary vars have positive coefficients,
7650 * thus we perform bound substitution with simple bounds (i.e. complementing) to achieve this.
7651 */
7652 while( i < *nnz )
7653 {
7654 SCIP_Real QUAD(coef);
7655 SCIP_Real simplebound;
7656 SCIP_Real bestlb;
7657 SCIP_Real bestub;
7658 SCIP_Bool setzero;
7659 int v = cutinds[i];
7660
7661 assert( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY );
7662
7663 assert(v < firstnonbinvar);
7664 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7665
7666 /* due to variable bound usage for bound substitution of continuous variables cancellation may have occurred */
7667 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
7668 {
7669 /* do not increase i, since last element is copied to the i-th position */
7670 setzero = TRUE;
7671 }
7672 else
7673 {
7674 /* perform bound substitution */
7675 if( QUAD_TO_DBL(coef) < 0.0 )
7676 {
7677 SCIP_CALL( findBestUb(scip, vars[v], sol, 0, allowlocal, &bestub, &simplebound, boundtype + i) );
7678
7679 if( SCIPisZero(scip, bestub) )
7680 {
7681 /* binary variable is fixed to zero */
7682 setzero = TRUE;
7683 *localbdsused = *localbdsused || (boundtype[i] == -2);
7684 }
7685 else
7686 {
7687 varsign[i] = -1;
7688
7689 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestub, v, localbdsused);
7690 QUAD_ARRAY_STORE(cutcoefs, v, -coef);
7691 setzero = FALSE;
7692 }
7693 }
7694 else
7695 {
7696 SCIP_CALL( findBestLb(scip, vars[v], sol, 0, allowlocal, &bestlb, &simplebound, boundtype + i) );
7697
7698 if( !SCIPisZero(scip, bestlb) )
7699 {
7700 /* binary variable is fixed to one */
7701 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlb, v, localbdsused);
7702 setzero = TRUE;
7703 }
7704 else
7705 {
7706 varsign[i] = +1;
7707 setzero = FALSE;
7708 }
7709 }
7710
7711 assert(boundtype[i] == -1 || boundtype[i] == -2);
7712 }
7713
7714 /* increase i or remove zero coefficient (i.e. var with 0 coef) by shifting last nonzero to current position */
7715 if( setzero )
7716 {
7717 QUAD_ASSIGN(coef, 0.0);
7718 QUAD_ARRAY_STORE(cutcoefs, v, coef);
7719 --(*nnz);
7720 cutinds[i] = cutinds[*nnz];
7721 }
7722 else
7723 ++i;
7724 }
7725
7726 /* relax rhs to zero if it is close to but slightly below zero */
7727 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
7728 QUAD_ASSIGN(*cutrhs, 0.0);
7729
7730 *success = TRUE;
7731 TERMINATE:
7732 /*free temporary memory */
7733 SCIPfreeBufferArray(scip, &bestbds);
7734
7735 return SCIP_OKAY;
7736}
7737
7738/** determines the initial cover for the given (fractional) knapsack row */
7739static
7741 SCIP* scip, /**< SCIP datastructure */
7742 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7743 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
7744 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
7745 SCIP_Real cutrhs, /**< pointer to the right hand side of the cut */
7746 int cutnnz, /**< pointer to the number of non-zeros in the cut */
7747 int* varsign, /**< sign of coefficients for each nonzero in the row be transformation */
7748 int* coverstatus, /**< array to return the coverstatus for each variable in the knapsack row */
7749 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
7750 SCIP_Real* covervals, /**< coefficient value of each variable in the cover */
7751 int* coversize, /**< pointer to return number of variables in the cover;
7752 * matches the length of the associated arrays */
7753 QUAD(SCIP_Real* coverweight) /**< pointer to return the weight of the cover;
7754 * the weight is the sum of the coefficient values of variables in the cover */
7755 )
7756{
7757 SCIP_VAR** vars;
7758 int k;
7759 int j;
7760 QUAD_ASSIGN(*coverweight, 0);
7761 *coversize = 0;
7762 j = cutnnz-1;
7763 vars = SCIPgetVars(scip);
7764
7765 for( k = 0; k < cutnnz; ++k )
7766 {
7767 SCIP_Real solval;
7768 int v = cutinds[k];
7769 SCIP_Real QUAD(coef);
7770 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7771
7772 solval = SCIPgetSolVal(scip, sol, vars[v]);
7773 if( varsign[k] == -1 )
7774 solval = 1 - solval;
7775
7776 if( SCIPisFeasEQ(scip, solval, 1.0) )
7777 {
7778 /* every variable with solution value 1 is forced into the cover */
7779 coverpos[*coversize] = k;
7780 covervals[*coversize] = QUAD_TO_DBL(coef);
7781 coverstatus[k] = 1;
7782 *coversize += 1;
7783 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
7784 }
7785 else
7786 {
7787 coverpos[j] = k;
7788 covervals[j] = solval * QUAD_TO_DBL(coef);
7789 coverstatus[k] = 0;
7790 j -= 1;
7791 }
7792 }
7793
7794 /* Use these two arrays to sort the variables by decreasing contribution
7795 * and pick them greedily in the while loop below until they are a cover.
7796 * Since the cover does not need to be minimal we do not need to remove any of the
7797 * variables with a high activity contribution even if they are not necessary after
7798 * picking the last variable.
7799 */
7800 SCIPsortDownRealInt(covervals + (*coversize), coverpos + (*coversize), cutnnz - (*coversize));
7801
7802 /* overwrite covervals with the coefficients of the variables in the cover
7803 * as we need to sort decreasingly by those again for the lifting
7804 */
7805 while( *coversize < cutnnz &&
7806 SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) )
7807 {
7808 int v;
7809 SCIP_Real QUAD(coef);
7810 k = coverpos[*coversize];
7811 v = cutinds[k];
7812 coverstatus[k] = 1;
7813 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7814 covervals[*coversize] = QUAD_TO_DBL(coef);
7815 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
7816 *coversize += 1;
7817 }
7818
7819 /* there is no cover */
7820 if( SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) || *coversize == 0 )
7821 return FALSE;
7822
7823 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(*coverweight), cutrhs);
7824 assert(*coversize > 0);
7825
7826 return TRUE;
7827}
7828
7829/** prepares the data needed to evaluate the lifting function */
7830static
7832 SCIP* scip, /**< SCIP datastructure */
7833 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
7834 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
7835 QUAD(SCIP_Real cutrhs), /**< pointer to the right hand side of the cut */
7836 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
7837 int coversize, /**< number of variables in the cover */
7838 QUAD(SCIP_Real coverweight), /**< weight of cover */
7839 SCIP_Real* covervals, /**< coefficient value of each variable in the cover;
7840 * on output stores the running sum of S^-(*) values */
7841 int* coverstatus, /**< coverstatus for each variable in the cover. After calling this function
7842 * variables in C^- will have the value -1, variables in C^+ the value 1,
7843 * and all variables outside the cover keep the value 0. */
7844 QUAD(SCIP_Real* abar), /**< pointer to store the reciprocal value of \bar{a} */
7845 int* cplussize /**< pointer to store the size of C^+ */
7846 )
7847{
7848 int k;
7849 SCIP_Real QUAD(tmp);
7850 SCIP_Real QUAD(sigma);
7851
7852 /* Now compute \bar{a}, the unique rational number such that for the cover C it holds that
7853 * b = \sum_{a_i \in C} \min(\bar{a}, a_i).
7854 * For that we need to sort by decreasing coefficients of the variables in the cover.
7855 * After the sorting the covervals array is free to be reused.
7856 */
7857 SCIPsortDownRealInt(covervals, coverpos, coversize);
7858
7859 /* Now follows Algorithm 1 in the paper to compute \bar{a} */
7860
7861 /* set \bar{a} = l_1 */
7862 QUAD_ARRAY_LOAD(*abar, cutcoefs, cutinds[coverpos[0]]);
7863 SCIPquadprecSumQQ(sigma, coverweight, -cutrhs);
7864
7865 for( k = 1; k < coversize; ++k )
7866 {
7867 SCIP_Real QUAD(lkplus1);
7868 SCIP_Real QUAD(kdelta);
7869
7870 /* load next coefficient l_{k+1} in sorted order of cover */
7871 QUAD_ARRAY_LOAD(lkplus1, cutcoefs, cutinds[coverpos[k]]);
7872
7873 /* Let \delta = \bar{a} - l_{k+1} and compute k * \delta */
7874 SCIPquadprecSumQQ(kdelta, *abar, -lkplus1);
7875 SCIPquadprecProdQD(kdelta, kdelta, k);
7876
7877 /* Set tmp = k * \delta - \sigma to check condition k * \delta < \sigma by tmp < 0 */
7878 SCIPquadprecSumQQ(tmp, kdelta, -sigma);
7879 if( QUAD_TO_DBL(tmp) < 0.0 )
7880 {
7881 /* Set \bar{a} = l_{k+1} and \sigma = \sigma - k*\delta */
7882 QUAD_ASSIGN_Q(*abar, lkplus1);
7883 SCIPquadprecSumQQ(sigma, sigma, -kdelta);
7884 }
7885 else
7886 {
7887 /* Set \bar{a} = \bar{a} - \sigma / k and \sigma = 0; break; */
7888 SCIP_Real minusoneoverk = -1.0 / k;
7889 SCIPquadprecProdQD(sigma, sigma, minusoneoverk);
7890 SCIPquadprecSumQQ(*abar, *abar, sigma);
7891 QUAD_ASSIGN(sigma, 0.0);
7892 break;
7893 }
7894 }
7895
7896 if( QUAD_TO_DBL(sigma) > 0.0 )
7897 {
7898 SCIP_Real oneoverc = 1.0 / coversize;
7899 SCIPquadprecProdQD(*abar, cutrhs, oneoverc);
7900 }
7901
7902 /* now we partition C into C^+ and C^-, where C^+ are all the elements of C whose weight is strictly larger than
7903 * \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
7904 * compute S^-(h) = sum of the h largest a_i^- and store S^-(h+1) in in covervals[h], for k = 0, ..., coversize - 1
7905 * (S^-(0) = 0 so it doesn't need to be stored; we use S to compute the lifted cut, see below)
7906 * we remember which elements of C^- in coverstatus, so that element in C^+ have coverstatus 1 and
7907 * elements in C^- have coverstatus -1 (elements not in C have coverstatus 0)
7908 */
7909 QUAD_ASSIGN(tmp, 0.0);
7910 *cplussize = 0;
7911 for( k = 0; k < coversize; ++k )
7912 {
7913 SCIP_Real QUAD(coef);
7914 SCIP_Real QUAD(coefminusabar);
7915
7916 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[coverpos[k]]);
7917 SCIPquadprecSumQQ(coefminusabar, coef, -*abar);
7918 if( QUAD_TO_DBL(coefminusabar) > 0.0 )
7919 {
7920 /* coefficient is in C^+ because it is greater than \bar{a} and contributes only \bar{a} to the sum */
7921 SCIPquadprecSumQQ(tmp, tmp, *abar);
7922
7923 /* rather be on the safe side in numerical corner cases and relax the coefficient to exactly \bar{a}.
7924 * In that case the coefficient is not treated as in C^+ but as being <= \bar{a} and therefore in C^-.
7925 */
7926 if( QUAD_TO_DBL(coefminusabar) > SCIPfeastol(scip) )
7927 ++(*cplussize);
7928 else
7929 coverstatus[coverpos[k]] = -1;
7930 }
7931 else
7932 {
7933 /* coefficient is in C^- because it is smaller or equal to \bar{a} */
7934 coverstatus[coverpos[k]] = -1;
7935 SCIPquadprecSumQQ(tmp, tmp, coef);
7936 }
7937 covervals[k] = QUAD_TO_DBL(tmp);
7938 SCIPdebugMsg(scip, "S^-(%d) = %g\n", k + 1, covervals[k]);
7939 }
7940
7941 /* set abar to its reciprocal for faster computation of the lifting coefficients */
7942 SCIPquadprecDivDQ(*abar, 1, *abar);
7943}
7944
7945/** evaluate the lifting function based on the given values */
7946static
7948 SCIP* scip, /**< SCIP datastructure */
7949 QUAD(SCIP_Real x), /**< value to evaluate the lifting function at */
7950 QUAD(SCIP_Real abar), /**< the reciprocal value of \bar{a} */
7951 SCIP_Real* covervals, /**< the running sum of S^-(*) values */
7952 int coversize, /**< the size of the cover */
7953 int cplussize, /**< the size of C^+ */
7954 SCIP_Real* scale /**< pointer to update the scale to integrality when a fractional value is returned */
7955 )
7956{
7957 SCIP_Real QUAD(tmp);
7958 SCIP_Real QUAD(hfrac);
7959 SCIP_Real cutcoef;
7960 SCIP_Real hreal;
7961 int h;
7962
7963 /* the lifted value is at least the coeficient (a_k) divided by \bar{a} because the largest value
7964 * contributed to the running sum stored in C is \bar{a}
7965 * therefore we start the search for the correct h at floor(a_k / \bar{a})
7966 */
7967
7968 SCIPdebugMsg(scip, "coef is %g, coversize is %d\n", QUAD_TO_DBL(x), coversize );
7969
7970 SCIPquadprecProdQQ(hfrac, x, abar);
7971
7972 /* if the coefficient is below \bar{a}, i.e. a / \bar{a} < 1 then g(a_k) = 0, otherwise g(a_k) > 0 */
7973 if( QUAD_TO_DBL(hfrac) < 1 )
7974 return 0.0;
7975
7976 /* we perform h = MIN(h, coversize) in floating-point first because on some instances h was seen to exceed the range
7977 * of int */
7978 hreal = SCIPfloor(scip, QUAD_TO_DBL(hfrac));
7979 if( hreal > (SCIP_Real)coversize )
7980 h = coversize;
7981 else
7982 h = (int)hreal;
7983
7984 SCIPquadprecSumQD(hfrac, hfrac, -h);
7985
7986 assert(h > 0);
7987 if( h < cplussize && ABS(QUAD_TO_DBL(hfrac)) <= QUAD_EPSILON )
7988 {
7989 /* cutcoef can be increased by 0.5 because it is a multiple of \bar{a}
7990 * (This is the first non-dominated lifting function presented in the paper)
7991 */
7992 cutcoef = 0.5;
7993 *scale = 2.0;
7994 }
7995 else
7996 cutcoef = 0.0;
7997
7998 /* decrease by one to make sure rounding errors or coefficients that are larger than the right hand side by themselves
7999 * did not push h too far */
8000 h--;
8001
8002 /* now increase coefficient to its lifted value based on its size relative to the S^- values.
8003 * The coefficient a_i is lifted to the unique integer h such that S^-(h) < a_i <= S^-(h+1).
8004 * (todo: variables that have a coefficient above the right hand side can get an arbitrarily large coefficient but can
8005 * also be trivially fixed using the base row. Currently they get the coefficient |C| which is 1 above the right hand
8006 * side in the cover cut so that they can still be trivially fixed by propagating the cover cut.
8007 * We do not want to apply fixings here though because the LP should stay flushed during separation.
8008 * Possibly add a parameter to return additional fixings to the caller of the SCIPcalc*() functions in here
8009 * and the caller can add them as cuts to the sepastore or we add them to the sepastore here?)
8010 */
8011 while( h < coversize )
8012 {
8013 SCIPquadprecSumQD(tmp, x, -covervals[h]); /* recall: covervals[h] = S^-(h+1) */
8014 /* compare with standard epsilon tolerance since computation involves abar, which is computed like an activity */
8015 if( !SCIPisPositive(scip, QUAD_TO_DBL(tmp)) )
8016 break;
8017
8018 ++h;
8019 }
8020
8021 cutcoef += h;
8022
8023 SCIPdebugMsg(scip, "x is %g, coversize is %d, h is %d\n", QUAD_TO_DBL(x), coversize, h );
8024 /* the lifted coefficient is h increased possibly by 0.5 for the case checked above */
8025 SCIPdebugMsg(scip, "lifted coef %g < %g <= %g to %g\n", h == 0 ? 0 : covervals[h-1], QUAD_TO_DBL(x),
8026 covervals[h], cutcoef);
8027
8028 return cutcoef;
8029}
8030
8031/** calculates a lifted knapsack cover cut out of the weighted sum of LP rows given by an aggregation row; the
8032 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
8033 * participate in the cut.
8034 * For further details we refer to:
8035 *
8036 * Letchford, A. N., & Souli, G. (2019). On lifted cover inequalities: A new lifting procedure with unusual properties.
8037 * Operations Research Letters, 47(2), 83-87.
8038 *
8039 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8040 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8041 *
8042 * @pre This method can be called if @p scip is in one of the following stages:
8043 * - \ref SCIP_STAGE_SOLVING
8044 *
8045 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
8046 */
8048 SCIP* scip, /**< SCIP data structure */
8049 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8050 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8051 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
8052 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
8053 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
8054 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
8055 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
8056 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
8057 int* cutrank, /**< pointer to return rank of generated cut */
8058 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
8059 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
8060 )
8061{
8062 int* varsign;
8063 int* boundtype;
8064 int* coverstatus;
8065 int* coverpos;
8066 int* tmpinds;
8067 SCIP_Real* tmpcoefs;
8068 SCIP_Real* covervals;
8069 SCIP_Real QUAD(rhs);
8070 SCIP_Real QUAD(coverweight);
8071 SCIP_Real QUAD(abar);
8072 SCIP_Bool transformed;
8073 SCIP_Bool local;
8074 SCIP_Real efficacy;
8075 SCIP_Real scale;
8076 int k;
8077 int nvars;
8078 int coversize;
8079 int cplussize;
8080 int nnz;
8081
8082 assert(scip != NULL);
8083 assert(aggrrow != NULL);
8084 assert(cutcoefs != NULL);
8085 assert(cutrhs != NULL);
8086 assert(cutinds != NULL);
8087 assert(cutnnz != NULL);
8088 assert(cutefficacy != NULL);
8089 assert(cutislocal != NULL);
8090 assert(success != NULL);
8091
8092 *success = FALSE;
8093
8094 if( aggrrow->nnz == 0 )
8095 return SCIP_OKAY;
8096
8097 for( k = 0; k < aggrrow->nrows; ++k )
8098 {
8099 /* cannot handle negative slack variables */
8100 if( aggrrow->rowweights[k] * aggrrow->slacksign[k] < 0 )
8101 return SCIP_OKAY;
8102 }
8103
8104 /* allocate temporary memory */
8105 nvars = SCIPgetNVars(scip);
8106 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
8107 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
8108 SCIP_CALL( SCIPallocBufferArray(scip, &coverstatus, nvars) );
8109 SCIP_CALL( SCIPallocBufferArray(scip, &covervals, nvars) );
8110 SCIP_CALL( SCIPallocBufferArray(scip, &coverpos, nvars) );
8111 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
8113
8114 /* initialize cut with aggregation */
8115 nnz = aggrrow->nnz;
8116 QUAD_ASSIGN_Q(rhs, aggrrow->rhs);
8117
8118 BMScopyMemoryArray(tmpinds, aggrrow->inds, nnz);
8119
8120 for( k = 0; k < nnz; ++k )
8121 {
8122 SCIP_Real QUAD(coef);
8123 int j = tmpinds[k];
8124
8125 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
8126
8127 QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
8128 assert(QUAD_HI(coef) != 0.0);
8129
8130 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
8131 }
8132 SCIPdebugMsg(scip, "Computing lifted knapsack cover for ");
8133 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
8134
8135 /* Transform aggregated row into a (fractional, i.e. with possibly fractional weights) knapsack constraint.
8136 * Uses simple or variable lower or upper bounds to relax out continuous and general integers
8137 * so that only binary variables remain and complements those such that they have a positive coefficient.
8138 */
8139 local = aggrrow->local;
8140 SCIP_CALL( cutsTransformKnapsackCover(scip, sol, allowlocal,
8141 tmpcoefs, QUAD(&rhs), tmpinds, &nnz, varsign, boundtype, &local, &transformed) );
8142
8143 assert(allowlocal || !local);
8144
8145 if( !transformed )
8146 goto TERMINATE;
8147
8148 SCIPdebugMsg(scip, "Transformed knapsack relaxation ");
8149 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
8150
8151 if( !computeInitialKnapsackCover(scip, sol, tmpcoefs, tmpinds, QUAD_TO_DBL(rhs), nnz, varsign, coverstatus,
8152 coverpos, covervals, &coversize, QUAD(&coverweight)) )
8153 goto TERMINATE;
8154
8155 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(coverweight), QUAD_TO_DBL(rhs));
8156 assert(coversize > 0);
8157
8158 /* by default do not scale the cut */
8159 scale = 1.0;
8160
8161 if( coversize == 1 )
8162 {
8163 SCIP_Real QUAD(tmp);
8164 /* cover is trivial, return the fixing as cut */
8165 QUAD_ASSIGN(tmp, 0.0);
8166 for( k = 0; k < nnz; ++k )
8167 {
8168 if( coverstatus[k] == 0 )
8169 {
8170 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
8171 }
8172 else
8173 {
8174 tmpinds[0] = tmpinds[k];
8175 varsign[0] = varsign[k];
8176 }
8177 }
8178
8179 nnz = 1;
8180 if( varsign[0] == -1 )
8181 {
8182 QUAD_ASSIGN(rhs, -1.0);
8183 QUAD_ASSIGN(tmp, -1.0);
8184 }
8185 else
8186 {
8187 QUAD_ASSIGN(rhs, 0.0);
8188 QUAD_ASSIGN(tmp, 1.0);
8189 }
8190
8191 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[0], tmp);
8192 }
8193 else
8194 {
8195 SCIP_Real QUAD(tmp);
8196
8197 /* compute lifted cover inequality:
8198 * sum_{i \in C^-) x_i + sum_{i \in N \ C^-) g(a_i) x_i <= c - 1
8199 * where g(z) is equal to
8200 * - 0 if z is 0 (irrelevant as there shouldn't be element with weight 0 in the knapsack)
8201 * - 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
8202 * - h if S^-(h) < z <= S^-(h+1) for some h = 0, ..., coversize -1
8203 * the function S^- is defined above. Note that S^-(0) = 0
8204 * we store the cut coefficients in tmpcoef
8205 */
8206
8207 SCIPdebugMsg(scip, "call prepareLiftingData: \n");
8208 /* prepare data required to evaluate lifting function */
8209 prepareLiftingData(scip, tmpcoefs, tmpinds, QUAD(rhs), coverpos, coversize,
8210 QUAD(coverweight), covervals, coverstatus, QUAD(&abar), &cplussize);
8211
8212 /* compute lifted cover inequality */
8213 QUAD_ASSIGN(rhs, (coversize - 1));
8214 for( k = 0; k < nnz; )
8215 {
8216 SCIP_Real cutcoef;
8217 if( coverstatus[k] == -1 )
8218 { /* variables in C^- get the coefficients 1 */
8219 cutcoef = 1.0;
8220 }
8221 else
8222 { /* variables is either in C^+ or not in the cover and its coefficient value is computed with the lifing function */
8223 SCIP_Real QUAD(coef);
8224
8225 SCIPdebugMsg(scip, "load QUAD(coef) from tmpcoefs[tmpinds[k] = %d]\n",tmpinds[k]);
8226 QUAD_ARRAY_LOAD(coef, tmpcoefs, tmpinds[k]);
8227
8228 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));
8229
8230 SCIPdebugMsg(scip, "call evaluateLiftingFunctionKnapsack:\n");
8231 cutcoef = evaluateLiftingFunctionKnapsack(scip, QUAD(coef), QUAD(abar), covervals, coversize, cplussize, &scale);
8232
8233 /* if the coefficient value is zero then remove the nonzero entry and continue */
8234 if( cutcoef == 0.0 )
8235 {
8236 QUAD_ASSIGN(tmp, 0.0);
8237 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
8238 --nnz;
8239 coverstatus[k] = coverstatus[nnz];
8240 tmpinds[k] = tmpinds[nnz];
8241 varsign[k] = varsign[nnz];
8242 continue;
8243 }
8244 }
8245
8246 /* directly undo the complementation before storing back the coefficient */
8247 if( varsign[k] == -1 )
8248 {
8249 /* variable was complemented so we have cutcoef * (1-x) = cutcoef - cutcoef * x.Thus we need to adjust the rhs
8250 * to rhs - cutcoef and flip the sign of cutcoef */
8251 cutcoef = -cutcoef;
8252 SCIPquadprecSumQD(rhs, rhs, cutcoef);
8253 }
8254
8255 QUAD_ASSIGN(tmp, cutcoef);
8256 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
8257
8258 ++k;
8259 }
8260 }
8261
8262 /* calculate the efficacy of the computed cut and store the success flag if the efficacy exceeds the
8263 * one stored in the cutefficacy variable by the caller
8264 */
8265 efficacy = calcEfficacyDenseStorageQuad(scip, sol, tmpcoefs, QUAD_TO_DBL(rhs), tmpinds, nnz);
8266 *success = efficacy > *cutefficacy;
8267
8268 SCIPdebugMsg(scip, "FINAL LCI:");
8269 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
8270
8271 if( *success )
8272 {
8273 /* return the cut into the given arrays/pointers */
8274 *cutislocal = local;
8275 *cutrhs = scale * QUAD_TO_DBL(rhs);
8276 *cutnnz = nnz;
8277
8278 /* store cut in given array in sparse representation and clean buffer array */
8279 for( k = 0; k < nnz; ++k )
8280 {
8281 SCIP_Real QUAD(coef);
8282 int j = tmpinds[k];
8283
8284 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
8285 assert(QUAD_HI(coef) != 0.0);
8286
8287 cutcoefs[k] = scale * QUAD_TO_DBL(coef);
8288 cutinds[k] = j;
8289 QUAD_ASSIGN(coef, 0.0);
8290 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
8291 }
8292
8293 assert( cutefficacy != NULL );
8294 /* calculate efficacy again to make sure it matches the coefficients after they where rounded to double values
8295 * and after the cleanup and postprocessing step was applied. */
8296 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, nnz);
8297
8298 if( cutrank != NULL )
8299 *cutrank = aggrrow->rank + 1;
8300 }
8301
8302 TERMINATE:
8303
8304 /* if we aborted early the tmpcoefs array needs to be cleaned */
8305 if( !(*success) )
8306 {
8307 SCIP_Real QUAD(tmp);
8308 QUAD_ASSIGN(tmp, 0.0);
8309
8310 for( k = 0; k < nnz; ++k )
8311 {
8312 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
8313 }
8314 }
8315#ifndef NDEBUG
8316 for( k = 0; k < QUAD_ARRAY_SIZE(nvars); ++k )
8317 {
8318 if(tmpcoefs[k] != 0.0)
8319 {
8320 SCIPdebugMsg(scip, "tmpcoefs have not been reset\n");
8321 SCIPABORT();
8322 }
8323 }
8324#endif
8325
8326 /* free temporary memory */
8327 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
8328 SCIPfreeBufferArray(scip, &tmpinds);
8329 SCIPfreeBufferArray(scip, &coverpos);
8330 SCIPfreeBufferArray(scip, &covervals);
8331 SCIPfreeBufferArray(scip, &coverstatus);
8332 SCIPfreeBufferArray(scip, &boundtype);
8333 SCIPfreeBufferArray(scip, &varsign);
8334
8335 return SCIP_OKAY;
8336}
8337
8338
8339/* =========================================== strongcg =========================================== */
8340
8341/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
8342 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
8343 *
8344 * Differs from cutsTransformMIR for continuous variables for which the lower bound must be used
8345 * when in case their coefficient is positive and the upper bound in case their coefficient is
8346 * negative. This forces all continuous variable to have a positive coefficient in the transformed
8347 * row.
8348 *
8349 * Transform variables (lb or ub):
8350 * \f[
8351 * \begin{array}{llll}
8352 * 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}\\
8353 * 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}
8354 * \end{array}
8355 * \f]
8356 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
8357 *
8358 * Transform variables (vlb or vub):
8359 * \f[
8360 * \begin{array}{llll}
8361 * 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.} \\
8362 * 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.}
8363 * \end{array}
8364 * \f]
8365 * 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:
8366 * \f[
8367 * \begin{array}{ll}
8368 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
8369 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
8370 * \end{array}
8371 * \f]
8372 */
8373static
8375 SCIP* scip, /**< SCIP data structure */
8376 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8377 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
8378 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
8379 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8380 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8381 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8382 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8383 int* nnz, /**< number of non-zeros in cut */
8384 int* varsign, /**< stores the sign of the transformed variable in summation */
8385 int* boundtype, /**< stores the bound used for transformed variable:
8386 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
8387 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
8388 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
8389 )
8390{
8391 SCIP_Real* bestbds;
8392 int i;
8393 int aggrrowintstart;
8394 int nvars;
8395 int firstcontvar;
8396 SCIP_VAR** vars;
8397
8398 assert(varsign != NULL);
8399 assert(boundtype != NULL);
8400 assert(freevariable != NULL);
8401 assert(localbdsused != NULL);
8402
8403 *freevariable = FALSE;
8404 *localbdsused = FALSE;
8405
8406 /* allocate temporary memory to store best bounds and bound types */
8407 SCIP_CALL( SCIPallocBufferArray(scip, &bestbds, 2*(*nnz)) );
8408
8409 /* start with continuous variables, because using variable bounds can affect the untransformed integral
8410 * variables, and these changes have to be incorporated in the transformation of the integral variables
8411 * (continuous variables have largest problem indices!)
8412 */
8413 SCIPsortDownInt(cutinds, *nnz);
8414
8415 vars = SCIPgetVars(scip);
8416 nvars = SCIPgetNVars(scip);
8417 firstcontvar = nvars - SCIPgetNContVars(scip);
8418
8419 /* determine best bounds for the continuous variables such that they will have a positive coefficient in the transformation */
8420 for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
8421 {
8422 SCIP_Real QUAD(coef);
8423 int v = cutinds[i];
8424
8425 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
8426
8427 if( QUAD_TO_DBL(coef) > 0.0 )
8428 {
8429 SCIP_Real simplebound;
8430
8431 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
8432 SCIP_CALL( findBestLb(scip, vars[v], sol, usevbds ? 2 : 0, allowlocal, bestbds + i, &simplebound, boundtype + i) );
8433
8434 /* cannot create transformation for strongcg cut */
8435 if( SCIPisInfinity(scip, -bestbds[i]) )
8436 {
8437 *freevariable = TRUE;
8438 goto TERMINATE;
8439 }
8440
8441 varsign[i] = +1;
8442 }
8443 else if( QUAD_TO_DBL(coef) < 0.0 )
8444 {
8445 SCIP_Real simplebound;
8446
8447 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
8448 SCIP_CALL( findBestUb(scip, vars[v], sol, usevbds ? 2 : 0, allowlocal, bestbds + i, &simplebound, boundtype + i) );
8449
8450 /* cannot create transformation for strongcg cut */
8451 if( SCIPisInfinity(scip, bestbds[i]) )
8452 {
8453 *freevariable = TRUE;
8454 goto TERMINATE;
8455 }
8456
8457 varsign[i] = -1;
8458 }
8459 }
8460
8461 /* remember start of integer variables in the aggrrow */
8462 aggrrowintstart = i;
8463
8464 /* perform bound substitution for continuous variables */
8465 for( i = 0; i < aggrrowintstart; ++i )
8466 {
8467 performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestbds[i], cutinds[i], localbdsused);
8468 }
8469
8470 assert(i == aggrrowintstart);
8471
8472 /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
8473 * and perform the bound substitution for the integer variables that are left using simple bounds
8474 */
8475 while( i < *nnz )
8476 {
8477 SCIP_Real QUAD(coef);
8478 SCIP_Real bestlb;
8479 SCIP_Real bestub;
8480 int bestlbtype;
8481 int bestubtype;
8482 SCIP_BOUNDTYPE selectedbound;
8483 int v = cutinds[i];
8484
8485 assert(v < firstcontvar);
8486 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
8487
8488 /* due to variable bound usage for the continuous variables cancellation may have occurred */
8489 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
8490 {
8491 QUAD_ASSIGN(coef, 0.0);
8492 QUAD_ARRAY_STORE(cutcoefs, v, coef);
8493 --(*nnz);
8494 cutinds[i] = cutinds[*nnz];
8495
8496 /* do not increase i, since last element is copied to the i-th position */
8497 continue;
8498 }
8499
8500 /* determine the best bounds for the integral variable, usevbd can be set to 0 here as vbds are only used for continuous variables */
8501 SCIP_CALL( determineBestBounds(scip, vars[v], sol, boundswitch, 0, allowlocal, FALSE, FALSE, NULL, NULL,
8502 &bestlb, &bestub, &bestlbtype, &bestubtype, &selectedbound, freevariable) );
8503
8504 /* check if we have an unbounded integral variable */
8505 if( *freevariable )
8506 {
8507 goto TERMINATE;
8508 }
8509
8510 /* perform bound substitution */
8511 if( selectedbound == SCIP_BOUNDTYPE_LOWER )
8512 {
8513 boundtype[i] = bestlbtype;
8514 varsign[i] = +1;
8515
8516 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlb, v, localbdsused);
8517 }
8518 else
8519 {
8520 assert(selectedbound == SCIP_BOUNDTYPE_UPPER);
8521 boundtype[i] = bestubtype;
8522 varsign[i] = -1;
8523
8524 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestub, v, localbdsused);
8525 }
8526
8527 assert(boundtype[i] == -1 || boundtype[i] == -2);
8528
8529 /* increase i */
8530 ++i;
8531 }
8532
8533 /* relax rhs to zero if it is close to */
8534 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
8535 QUAD_ASSIGN(*cutrhs, 0.0);
8536
8537 TERMINATE:
8538 /* free temporary memory */
8539 SCIPfreeBufferArray(scip, &bestbds);
8540
8541 return SCIP_OKAY;
8542}
8543
8544/** Calculate fractionalities \f$ f_0 := b - down(b) \f$, \f$ f_j := a^\prime_j - down(a^\prime_j) \f$,
8545 * 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
8546 * 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$
8547 * and derive strong CG cut \f$ \tilde{a} x^\prime \leq down(b) \f$
8548 * \f[
8549 * \begin{array}{rll}
8550 * integers : & \tilde{a}_j = down(a^\prime_j) &, if \qquad f_j \leq f_0 \\
8551 * & \tilde{a}_j = down(a^\prime_j) + p_j/(k + 1) &, if \qquad f_j > f_0 \\
8552 * continuous:& \tilde{a}_j = 0 &, if \qquad a^\prime_j \geq 0 \\
8553 * & \mbox{no strong CG cut found} &, if \qquad a^\prime_j < 0
8554 * \end{array}
8555 * \f]
8556 *
8557 * Transform inequality back to \f$ \hat{a}*x <= rhs \f$:
8558 *
8559 * (lb or ub):
8560 * \f[
8561 * \begin{array}{lllll}
8562 * 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} \\
8563 * 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}
8564 * \end{array}
8565 * \f]
8566 * \f[
8567 * and move the constant terms
8568 * \begin{array}{rl}
8569 * -\tilde{a}_j * lb_j == -\hat{a}_j * lb_j, & \mbox{or} \\
8570 * \tilde{a}_j * ub_j == -\hat{a}_j * ub_j &
8571 * \end{array}
8572 * \f]
8573 * to the rhs.
8574 *
8575 * (vlb or vub):
8576 * \f[
8577 * \begin{array}{lllll}
8578 * 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)} \\
8579 * 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)}
8580 * \end{array}
8581 * \f]
8582 * move the constant terms
8583 * \f[
8584 * \begin{array}{rl}
8585 * -\tilde{a}_j * dl_j == -\hat{a}_j * dl_j,& \mbox{or} \\
8586 * \tilde{a}_j * du_j == -\hat{a}_j * du_j &
8587 * \end{array}
8588 * \f]
8589 * to the rhs, and update the VB variable coefficients:
8590 * \f[
8591 * \begin{array}{ll}
8592 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j * bl_j == \hat{a}_{zl_j} - \hat{a}_j * bl_j,& \mbox{or} \\
8593 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j * bu_j == \hat{a}_{zu_j} - \hat{a}_j * bu_j &
8594 * \end{array}
8595 * \f]
8596 */
8597static
8599 SCIP* scip, /**< SCIP data structure */
8600 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8601 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8602 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8603 int* nnz, /**< number of non-zeros in cut */
8604 int* varsign, /**< stores the sign of the transformed variable in summation */
8605 int* boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub)*/
8606 QUAD(SCIP_Real f0), /**< fractional value of rhs */
8607 SCIP_Real k /**< factor to strengthen strongcg cut */
8608 )
8609{
8610 SCIP_Real QUAD(onedivoneminusf0);
8611 int i;
8612 int firstcontvar;
8613 SCIP_VAR** vars;
8614 int aggrrowintstart;
8615
8616 assert(QUAD_HI(cutrhs) != NULL);
8617 assert(cutcoefs != NULL);
8618 assert(cutinds != NULL);
8619 assert(nnz != NULL);
8620 assert(boundtype != NULL);
8621 assert(varsign != NULL);
8622 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
8623
8624 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
8625 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
8626
8627 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
8628 * without destroying the ordering of the aggrrow's non-zeros.
8629 * (due to sorting in cutsTransformStrongCG the ordering is continuous before integral)
8630 */
8631
8632 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
8633 vars = SCIPgetVars(scip);
8634#ifndef NDEBUG
8635 /* in debug mode check, that all continuous variables of the aggrrow come before the integral variables */
8636 i = 0;
8637 while( i < *nnz && cutinds[i] >= firstcontvar )
8638 {
8639 assert(SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_CONTINUOUS);
8640 ++i;
8641 }
8642 while( i < *nnz )
8643 {
8644 assert(cutinds[i] < firstcontvar);
8645 assert(SCIPvarGetType(vars[cutinds[i]]) != SCIP_VARTYPE_CONTINUOUS);
8646 ++i;
8647 }
8648#endif
8649
8650 /* integer variables */
8651 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
8652 {
8653 SCIP_VAR* var;
8654 SCIP_Real QUAD(aj);
8655 SCIP_Real QUAD(downaj);
8656 SCIP_Real QUAD(cutaj);
8657 SCIP_Real QUAD(fj);
8658 SCIP_Real QUAD(tmp);
8660 int v;
8661
8662 v = cutinds[i];
8663 assert(0 <= v && v < SCIPgetNVars(scip));
8664
8665 var = vars[v];
8666 assert(var != NULL);
8667 assert(SCIPvarGetProbindex(var) == v);
8668 assert(boundtype[i] == -1 || boundtype[i] == -2);
8669 assert(varsign[i] == +1 || varsign[i] == -1);
8670
8671 /* calculate the coefficient in the retransformed cut */
8672 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
8673 QUAD_SCALE(aj, varsign[i]);
8674 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
8675 SCIPquadprecSumQQ(fj, aj, -downaj);
8676 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
8677
8678 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
8679 QUAD_ASSIGN_Q(cutaj, downaj); /* a_j */
8680 else
8681 {
8682 SCIP_Real pj;
8683
8684 SCIPquadprecSumQQ(cutaj, fj, -f0);
8685 SCIPquadprecProdQD(cutaj, cutaj, k);
8686 SCIPquadprecProdQQ(cutaj, cutaj, onedivoneminusf0);
8687 pj = SCIPceil(scip, QUAD_TO_DBL(cutaj));
8688 assert(pj >= 0); /* should be >= 1, but due to rounding bias can be 0 if fj is almost equal to f0 */
8689 assert(pj <= k);
8690 SCIPquadprecDivDD(cutaj, pj, k + 1.0);
8691 SCIPquadprecSumQQ(cutaj, cutaj, downaj);
8692 }
8693
8694 QUAD_SCALE(cutaj, varsign[i]);
8695
8696 /* remove zero cut coefficients from cut */
8697 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
8698 {
8699 QUAD_ASSIGN(cutaj, 0.0);
8700 QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
8701 --*nnz;
8702 cutinds[i] = cutinds[*nnz];
8703 continue;
8704 }
8705
8706 QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
8707
8708 /* integral var uses standard bound */
8709 assert(boundtype[i] < 0);
8710
8711 /* move the constant term -\tilde{a}_j * lb_j == -a_j * lb_j , or \tilde{a}_j * ub_j == -a_j * ub_j to the rhs */
8712 if( varsign[i] == +1 )
8713 {
8714 /* lower bound was used */
8715 if( boundtype[i] == -1 )
8717 else
8718 bound = SCIPvarGetLbLocal(var);
8719 assert(!SCIPisInfinity(scip, -bound));
8720 }
8721 else
8722 {
8723 /* upper bound was used */
8724 if( boundtype[i] == -1 )
8726 else
8727 bound = SCIPvarGetUbLocal(var);
8728 assert(!SCIPisInfinity(scip, bound));
8729 }
8730 SCIPquadprecProdQD(tmp, cutaj, bound);
8731 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
8732 }
8733
8734 /* now process the continuous variables; postpone deletion of zeros until all continuous variables have been processed */
8735 aggrrowintstart = i + 1;
8736
8737#ifndef NDEBUG
8738 /* in a strong CG cut, cut coefficients of continuous variables are always zero; check this in debug mode */
8739 for( i = 0; i < aggrrowintstart; ++i )
8740 {
8741 SCIP_Real QUAD(aj);
8742 SCIP_VAR* var;
8743 int v;
8744
8745 v = cutinds[i];
8746 assert(firstcontvar <= v && v < SCIPgetNVars(scip));
8747
8748 var = vars[v];
8749 assert(var != NULL);
8750 assert(!SCIPvarIsIntegral(var));
8751 assert(SCIPvarGetProbindex(var) == v);
8752 assert(varsign[i] == +1 || varsign[i] == -1);
8753
8754 /* calculate the coefficient in the retransformed cut */
8755 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
8756 QUAD_SCALE(aj, varsign[i]);
8757
8758 assert(QUAD_TO_DBL(aj) >= 0.0);
8759 }
8760#endif
8761
8762 /* set continuous variable coefficients to 0 */
8763 if( aggrrowintstart > 0 )
8764 {
8765 SCIP_Real QUAD(tmp);
8766 assert(aggrrowintstart <= *nnz);
8767
8768 /* explicitly set continuous variable coefficients to 0 */
8769 QUAD_ASSIGN(tmp, 0.0);
8770 for( i = 0; i < aggrrowintstart; ++i )
8771 {
8772 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], tmp);
8773 }
8774
8775 /* fill empty positions of the continuous variables by integral variables; copy all indices to the front or only
8776 * use the indices at the end, whatever is faster */
8777 *nnz -= aggrrowintstart;
8778 if( *nnz < aggrrowintstart )
8779 {
8780 BMScopyMemoryArray(cutinds, cutinds + aggrrowintstart, *nnz);
8781 }
8782 else
8783 {
8784 BMScopyMemoryArray(cutinds, cutinds + *nnz, aggrrowintstart);
8785 }
8786 }
8787
8788 return SCIP_OKAY;
8789}
8790
8791/** substitute aggregated slack variables:
8792 *
8793 * 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
8794 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r] \f$.
8795 *
8796 * Depending on the slack's type (integral or continuous), its coefficient in the cut calculates as follows:
8797 * \f[
8798 * \begin{array}{rll}
8799 * integers: & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & if \qquad f_r \leq f_0 \\
8800 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + p_r/(k + 1), & if \qquad f_r > f_0 \\
8801 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & if \qquad a^\prime_r \geq 0 \\
8802 * & \mbox{no strong CG cut found}, & if \qquad a^\prime_r < 0
8803 * \end{array}
8804 * \f]
8805 *
8806 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
8807 */
8808static
8810 SCIP* scip, /**< SCIP datastructure */
8811 SCIP_Real* weights, /**< row weights in row summation */
8812 int* slacksign, /**< stores the sign of the row's slack variable in summation */
8813 int* rowinds, /**< sparsity pattern of used rows */
8814 int nrowinds, /**< number of used rows */
8815 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
8816 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8817 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8818 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8819 int* nnz, /**< number of non-zeros in cut */
8820 QUAD(SCIP_Real f0), /**< fractional value of rhs */
8821 SCIP_Real k /**< factor to strengthen strongcg cut */
8822 )
8823{ /*lint --e{715}*/
8824 SCIP_ROW** rows;
8825 SCIP_Real QUAD(onedivoneminusf0);
8826 int i;
8827
8828 assert(scip != NULL);
8829 assert(weights != NULL);
8830 assert(slacksign != NULL);
8831 assert(rowinds != NULL);
8832 assert(SCIPisPositive(scip, scale));
8833 assert(cutcoefs != NULL);
8834 assert(QUAD_HI(cutrhs) != NULL);
8835 assert(cutinds != NULL);
8836 assert(nnz != NULL);
8837 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
8838
8839 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
8840 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
8841
8842 rows = SCIPgetLPRows(scip);
8843 for( i = 0; i < nrowinds; i++ )
8844 {
8845 SCIP_ROW* row;
8846 SCIP_Real QUAD(ar);
8847 SCIP_Real QUAD(downar);
8848 SCIP_Real QUAD(cutar);
8849 SCIP_Real QUAD(fr);
8850 SCIP_Real mul;
8851 int r;
8852
8853 r = rowinds[i];
8854 assert(0 <= r && r < SCIPgetNLPRows(scip));
8855 assert(slacksign[i] == -1 || slacksign[i] == +1);
8856 assert(!SCIPisZero(scip, weights[i]));
8857
8858 row = rows[r];
8859 assert(row != NULL);
8860 assert(row->len == 0 || row->cols != NULL);
8861 assert(row->len == 0 || row->cols_index != NULL);
8862 assert(row->len == 0 || row->vals != NULL);
8863
8864 /* get the slack's coefficient a'_r in the aggregated row */
8865 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
8866
8867 /* calculate slack variable's coefficient a_r in the cut */
8868 if( row->integral )
8869 {
8870 /* slack variable is always integral */
8871 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
8872 SCIPquadprecSumQQ(fr, ar, -downar);
8873 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
8874
8875 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
8876 QUAD_ASSIGN_Q(cutar, downar); /* a_r */
8877 else
8878 {
8879 SCIP_Real pr;
8880
8881 SCIPquadprecSumQQ(cutar, fr, -f0);
8882 SCIPquadprecProdQD(cutar, cutar, k);
8883 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
8884 pr = SCIPceil(scip, QUAD_TO_DBL(cutar));
8885 assert(pr >= 0); /* should be >= 1, but due to rounding bias can be 0 if fr is almost equal to f0 */
8886 assert(pr <= k);
8887 SCIPquadprecDivDD(cutar, pr, k + 1.0);
8888 SCIPquadprecSumQQ(cutar, cutar, downar);
8889 }
8890 }
8891 else
8892 {
8893 /* slack variable is continuous: */
8894 assert(QUAD_TO_DBL(ar) >= 0.0);
8895 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
8896 }
8897
8898 /* if the coefficient was reduced to zero, ignore the slack variable */
8899 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
8900 continue;
8901
8902 /* depending on the slack's sign, we have
8903 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
8904 * substitute a_r * s_r by adding a_r times the slack's definition to the cut.
8905 */
8906 mul = -slacksign[i] * QUAD_TO_DBL(cutar);
8907
8908 /* add the slack's definition multiplied with a_j to the cut */
8909 SCIP_CALL( varVecAddScaledRowCoefsQuad(cutinds, cutcoefs, nnz, row, mul) );
8910
8911 /* move slack's constant to the right hand side */
8912 if( slacksign[i] == +1 )
8913 {
8914 SCIP_Real rhs;
8915
8916 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a_r * (rhs - c) to the right hand side */
8917 assert(!SCIPisInfinity(scip, row->rhs));
8918 rhs = row->rhs - row->constant;
8919 if( row->integral )
8920 {
8921 /* the right hand side was implicitly rounded down in row aggregation */
8922 rhs = SCIPfloor(scip, rhs);
8923 }
8924
8925 SCIPquadprecProdQD(cutar, cutar, rhs);
8926 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -cutar);
8927 }
8928 else
8929 {
8930 SCIP_Real lhs;
8931
8932 /* a*x + c - s == lhs => s == a*x + c - lhs: move a_r * (c - lhs) to the right hand side */
8933 assert(!SCIPisInfinity(scip, -row->lhs));
8934 lhs = row->lhs - row->constant;
8935 if( row->integral )
8936 {
8937 /* the left hand side was implicitly rounded up in row aggregation */
8938 lhs = SCIPceil(scip, lhs);
8939 }
8940
8941 SCIPquadprecProdQD(cutar, cutar, lhs);
8942 SCIPquadprecSumQQ(*cutrhs, *cutrhs, cutar);
8943 }
8944 }
8945
8946 /* relax rhs to zero, if it's very close to 0 */
8947 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
8948 QUAD_ASSIGN(*cutrhs, 0.0);
8949
8950 return SCIP_OKAY;
8951}
8952
8953
8954/** calculates a strong CG cut out of the weighted sum of LP rows given by an aggregation row; the
8955 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
8956 * participate in a strongcg cut
8957 *
8958 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8959 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8960 *
8961 * @pre This method can be called if @p scip is in one of the following stages:
8962 * - \ref SCIP_STAGE_SOLVING
8963 *
8964 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
8965 */
8967 SCIP* scip, /**< SCIP data structure */
8968 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8969 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
8970 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
8971 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
8972 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8973 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce strong CG cut for */
8974 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce strong CG cut for */
8975 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
8976 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute a strong CG cut for */
8977 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
8978 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
8979 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
8980 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
8981 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
8982 int* cutrank, /**< pointer to return rank of generated cut */
8983 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
8984 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
8985 )
8986{
8987 int i;
8988 int nvars;
8989 int* varsign;
8990 int* boundtype;
8991 SCIP_Real* tmpcoefs;
8992 SCIP_Real QUAD(downrhs);
8993 SCIP_Real QUAD(f0);
8994 SCIP_Real QUAD(tmp);
8995 SCIP_Real QUAD(rhs);
8996 SCIP_Real large;
8997 SCIP_Real k;
8998 SCIP_Bool freevariable;
8999 SCIP_Bool localbdsused;
9000
9001 assert(scip != NULL);
9002 assert(aggrrow != NULL);
9003 assert(SCIPisPositive(scip, scale));
9004 assert(cutcoefs != NULL);
9005 assert(cutrhs != NULL);
9006 assert(cutinds != NULL);
9007 assert(success != NULL);
9008 assert(cutislocal != NULL);
9009
9010 SCIPdebugMsg(scip, "calculating strong CG cut (scale: %g)\n", scale);
9011
9012 *success = FALSE;
9013
9014 /* determine value from which fractionalities are no longer reliable within tolerance */
9016
9017 /* terminate if an integral slack fractionality is unreliable or a negative continuous slack variable is present */
9018 for( i = 0; i < aggrrow->nrows; ++i )
9019 if( ( scip->lp->rows[aggrrow->rowsinds[i]]->integral && ABS(aggrrow->rowweights[i] * scale) > large )
9020 || ( !scip->lp->rows[aggrrow->rowsinds[i]]->integral && aggrrow->rowweights[i] * aggrrow->slacksign[i] < 0.0 ) )
9021 return SCIP_OKAY;
9022
9023 /* allocate temporary memory */
9024 nvars = SCIPgetNVars(scip);
9025 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
9026 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
9028
9029 /* initialize cut with aggregation */
9030 *cutnnz = aggrrow->nnz;
9031 *cutislocal = aggrrow->local;
9032 SCIPquadprecProdQD(rhs, aggrrow->rhs, scale);
9033
9034 if( *cutnnz > 0 )
9035 {
9036 int firstcontvar;
9037
9038 BMScopyMemoryArray(cutinds, aggrrow->inds, *cutnnz);
9039
9040 for( i = 0; i < *cutnnz; ++i )
9041 {
9042 SCIP_Real QUAD(coef);
9043 int j = cutinds[i];
9044
9045 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
9046 SCIPquadprecProdQD(coef, coef, scale);
9047
9048 QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
9049 assert(QUAD_HI(coef) != 0.0);
9050
9051 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
9052 }
9053
9054 /* Transform equation a*x == b, lb <= x <= ub into standard form
9055 * a'*x' == b, 0 <= x' <= ub'.
9056 *
9057 * Transform variables (lb or ub):
9058 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
9059 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
9060 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
9061 *
9062 * Transform variables (vlb or vub):
9063 * 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.
9064 * 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.
9065 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
9066 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
9067 * a_{zu_j} := a_{zu_j} + a_j * bu_j
9068 */
9069 SCIP_CALL( cutsTransformStrongCG(scip, sol, boundswitch, usevbds, allowlocal,
9070 tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, &freevariable, &localbdsused) );
9071
9072 assert(allowlocal || !localbdsused);
9073 *cutislocal = *cutislocal || localbdsused;
9074
9075 if( freevariable )
9076 goto TERMINATE;
9077
9078 firstcontvar = nvars - SCIPgetNContVars(scip);
9079
9080 /* terminate if an integral coefficient fractionality is unreliable */
9081 for( i = *cutnnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
9082 {
9083 SCIP_Real QUAD(coef);
9084
9085 QUAD_ARRAY_LOAD(coef, tmpcoefs, cutinds[i]);
9086
9087 if( ABS(QUAD_TO_DBL(coef)) > large )
9088 goto TERMINATE;
9089 }
9090
9091 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
9092 }
9093
9094 /* terminate if the side fractionality is unreliable */
9095 if( ABS(QUAD_TO_DBL(rhs)) > large )
9096 goto TERMINATE;
9097
9098 /* Calculate
9099 * - fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j)
9100 * - integer k >= 1 with 1/(k + 1) <= f_0 < 1/k
9101 * (=> k = up(1/f_0) - 1)
9102 * - 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)
9103 * (=> p_j = up( (f_j - f_0)/((1 - f_0)/k) ))
9104 * and derive strong CG cut
9105 * a~*x' <= (k+1) * down(b)
9106 * integers : a~_j = down(a'_j) , if f_j <= f_0
9107 * a~_j = down(a'_j) + p_j/(k + 1) , if f_j > f_0
9108 * continuous: a~_j = 0 , if a'_j >= 0
9109 * no strong CG cut found , if a'_j < 0
9110 *
9111 * Transform inequality back to a^*x <= rhs:
9112 *
9113 * (lb or ub):
9114 * 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
9115 * 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
9116 * and move the constant terms
9117 * -a~_j * lb_j == -a^_j * lb_j, or
9118 * a~_j * ub_j == -a^_j * ub_j
9119 * to the rhs.
9120 *
9121 * (vlb or vub):
9122 * 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)
9123 * 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)
9124 * move the constant terms
9125 * -a~_j * dl_j == -a^_j * dl_j, or
9126 * a~_j * du_j == -a^_j * du_j
9127 * to the rhs, and update the VB variable coefficients:
9128 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
9129 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
9130 */
9131 SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
9132 SCIPquadprecSumQQ(f0, rhs, -downrhs);
9133 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
9134
9135 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
9136 goto TERMINATE;
9137
9138 /* renormalize the f0 value */
9139 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
9140
9141 SCIPquadprecDivDQ(tmp, 1.0, f0);
9142 SCIPquadprecSumQD(tmp, tmp, -1.0);
9143 k = SCIPceil(scip, QUAD_TO_DBL(tmp));
9144 QUAD_ASSIGN_Q(rhs, downrhs);
9145
9146 if( *cutnnz > 0 )
9147 {
9148 SCIP_CALL( cutsRoundStrongCG(scip, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, QUAD(f0), k) );
9149 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
9150 }
9151
9152 /* substitute aggregated slack variables:
9153 *
9154 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
9155 * variable only appears in its own row:
9156 * a'_r = scale * weight[r] * slacksign[r].
9157 *
9158 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
9159 * integers : a_r = a~_r = (k + 1) * down(a'_r) , if f_r <= f0
9160 * a_r = a~_r = (k + 1) * down(a'_r) + p_r , if f_r > f0
9161 * continuous: a_r = a~_r = 0 , if a'_r >= 0
9162 * a_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
9163 *
9164 * Substitute a_r * s_r by adding a_r times the slack's definition to the cut.
9165 */
9166 SCIP_CALL( cutsSubstituteStrongCG(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
9167 aggrrow->nrows, scale, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, QUAD(f0), k) );
9168 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
9169
9170 /* remove all nearly-zero coefficients from strong CG row and relax the right hand side correspondingly in order to
9171 * prevent numerical rounding errors
9172 */
9173 if( postprocess )
9174 {
9175 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, cutinds, tmpcoefs, cutnnz, QUAD(&rhs), success) );
9176 }
9177 else
9178 {
9179 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, tmpcoefs, QUAD(&rhs), cutinds, cutnnz);
9180 }
9181 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
9182
9183 if( *success )
9184 {
9185 *cutrhs = QUAD_TO_DBL(rhs);
9186
9187 /* store cut in given array in sparse representation and clean buffer array */
9188 for( i = 0; i < *cutnnz; ++i )
9189 {
9190 SCIP_Real QUAD(coef);
9191 int j = cutinds[i];
9192
9193 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
9194 assert(QUAD_HI(coef) != 0.0);
9195
9196 cutcoefs[i] = QUAD_TO_DBL(coef);
9197 QUAD_ASSIGN(coef, 0.0);
9198 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
9199 }
9200
9201 if( cutefficacy != NULL )
9202 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
9203
9204 if( cutrank != NULL )
9205 *cutrank = aggrrow->rank + 1;
9206 }
9207
9208 TERMINATE:
9209
9210 /* if we aborted early the tmpcoefs array needs to be cleaned */
9211 if( !(*success) )
9212 {
9213 QUAD_ASSIGN(tmp, 0.0);
9214
9215 for( i = 0; i < *cutnnz; ++i )
9216 {
9217 QUAD_ARRAY_STORE(tmpcoefs, cutinds[i], tmp);
9218 }
9219 }
9220
9221 /* free temporary memory */
9222 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
9223 SCIPfreeBufferArray(scip, &boundtype);
9224 SCIPfreeBufferArray(scip, &varsign);
9225
9226 return SCIP_OKAY;
9227}
static long bound
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:167
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:4130
static SCIP_RETCODE cutsTransformMIR(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 minfrac, SCIP_Real maxfrac, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition: cuts.c:3052
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:2997
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:7831
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:7541
static SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
Definition: cuts.c:656
static SCIP_RETCODE findBestLb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, SCIP_Real *simplebound, int *bestlbtype)
Definition: cuts.c:2596
static SCIP_Real calcEfficacyDenseStorageQuad(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:396
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:471
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:8809
static SCIP_RETCODE computeLiftingData(SCIP *scip, SNF_RELAXATION *snf, int *transvarflowcoverstatus, SCIP_Real lambda, LIFTINGDATA *liftingdata, SCIP_Bool *valid)
Definition: cuts.c:6993
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:4961
static SCIP_RETCODE getFlowCover(SCIP *scip, SNF_RELAXATION *snf, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, SCIP_Real *lambda, SCIP_Bool *found)
Definition: cuts.c:6605
static SCIP_RETCODE determineBestBounds(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:2718
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:5091
static SCIP_RETCODE cutsTransformStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition: cuts.c:8374
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:7947
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:701
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:746
#define MAXBOUND
Definition: cuts.c:4913
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:5400
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:2412
static SCIP_RETCODE cutsRoundMIR(SCIP *scip, SCIP_Real *RESTRICT cutcoefs, QUAD(SCIP_Real *RESTRICT cutrhs), int *RESTRICT cutinds, int *RESTRICT nnz, int *RESTRICT varsign, int *RESTRICT boundtype, QUAD(SCIP_Real f0))
Definition: cuts.c:3408
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:2917
static void destroyLiftingData(SCIP *scip, LIFTINGDATA *liftingdata)
Definition: cuts.c:7123
static SCIP_RETCODE varVecAddScaledRowCoefsQuad(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:174
static SCIP_Real calcEfficacyNormQuad(SCIP *scip, SCIP_Real *vals, int *inds, int nnz)
Definition: cuts.c:334
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:1168
#define NONZERO(x)
Definition: cuts.c:123
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:564
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:5994
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:5219
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:2343
static void destroySNFRelaxation(SCIP *scip, SNF_RELAXATION *snf)
Definition: cuts.c:5974
static SCIP_RETCODE allocSNFRelaxation(SCIP *scip, SNF_RELAXATION *snf, int nvars)
Definition: cuts.c:5953
static SCIP_RETCODE cutsRoundStrongCG(SCIP *scip, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, QUAD(SCIP_Real f0), SCIP_Real k)
Definition: cuts.c:8598
static SCIP_Real calcEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:269
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:6089
#define MAXCMIRSCALE
Definition: cuts.c:2592
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:7136
static void getAlphaAndBeta(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real vubcoef, int *alpha, SCIP_Real *beta)
Definition: cuts.c:6956
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:3719
#define MAXABSVBCOEF
Definition: cuts.c:4912
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:2170
static SCIP_RETCODE varVecAddScaledRowCoefsQuadScale(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, QUAD(SCIP_Real scale))
Definition: cuts.c:221
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:793
static SCIP_Real evaluateLiftingFunction(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real x)
Definition: cuts.c:6872
static SCIP_RETCODE varVecAddScaledRowCoefs(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:129
static SCIP_RETCODE findBestUb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, SCIP_Real *simplebound, int *bestubtype)
Definition: cuts.c:2657
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:7740
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:267
#define COPYSIGN
Definition: def.h:258
#define SCIP_Longint
Definition: def.h:158
#define SCIP_UNUSED(x)
Definition: def.h:428
#define EPSISINT(x, eps)
Definition: def.h:210
#define SCIP_REAL_MAX
Definition: def.h:174
#define SCIP_INVALID
Definition: def.h:193
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:243
#define SCIP_Real
Definition: def.h:173
#define ABS(x)
Definition: def.h:235
#define EPSFRAC(x, eps)
Definition: def.h:209
#define SQR(x)
Definition: def.h:214
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:239
#define SCIP_CALL_ABORT(x)
Definition: def.h:353
#define RESTRICT
Definition: def.h:279
#define SCIPABORT()
Definition: def.h:346
#define REALABS(x)
Definition: def.h:197
#define EPSZ(x, eps)
Definition: def.h:203
#define SCIP_CALL(x)
Definition: def.h:374
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 SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2172
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1866
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2037
#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_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:9557
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11184
void SCIPaggrRowCancelVarWithBound(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_VAR *var, int pos, SCIP_Bool *valid)
Definition: cuts.c:1945
SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
Definition: cuts.c:2518
int SCIPaggrRowGetRank(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2561
SCIP_RETCODE SCIPcutGenerationHeuristicCMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, 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:4212
SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
Definition: cuts.c:1527
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1723
SCIP_RETCODE SCIPcalcStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, 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:8966
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:8047
void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2133
SCIP_RETCODE SCIPaggrRowCopy(SCIP *scip, SCIP_AGGRROW **aggrrow, SCIP_AGGRROW *source)
Definition: cuts.c:1813
SCIP_Bool SCIPaggrRowIsLocal(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2571
SCIP_Real SCIPaggrRowGetRhs(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2581
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2486
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:2080
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1755
int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2541
void SCIPaggrRowPrint(SCIP *scip, SCIP_AGGRROW *aggrrow, FILE *file)
Definition: cuts.c:1776
void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool useglbbounds, SCIP_Bool *valid)
Definition: cuts.c:2471
SCIP_Real * SCIPaggrRowGetRowWeights(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2507
int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2551
SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
Definition: cuts.c:1859
int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2496
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:2279
int SCIPgetNCuts(SCIP *scip)
Definition: scip_cut.c:787
SCIP_RETCODE SCIPaggrRowAddObjectiveFunction(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real rhs, SCIP_Real scale)
Definition: cuts.c:2004
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:7417
SCIP_Real SCIPaggrRowCalcEfficacyNorm(SCIP *scip, SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2158
SCIP_RETCODE SCIPcalcMIR(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:3873
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:570
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:605
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:626
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip_mem.h:146
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip_mem.h:142
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
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 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_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17292
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:17411
SCIP_Real SCIPgetRowMinActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1939
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17302
SCIP_Real SCIPgetRowMaxActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1956
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17501
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17401
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition: lp.c:17340
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2144
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
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:18270
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18292
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17748
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17599
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18144
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17926
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17584
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18088
SCIP_RETCODE SCIPgetVarClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvub, int *closestvubidx)
Definition: scip_var.c:6632
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17768
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17419
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18302
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18312
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17610
SCIP_RETCODE SCIPgetVarClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: scip_var.c:6609
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:18452
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18134
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18282
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18078
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18344
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18324
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18334
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)
static SCIP_Bool isIntegralScalar(SCIP_Real val, SCIP_Real scalar, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Real *intval)
Definition: lp.c:4900
internal methods for LP management
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
#define MAXSCALE
#define MAXDELTA
#define MINDELTA
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
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
public methods for cuts and aggregation rows
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for 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:4920
SCIP_Real lambda
Definition: cuts.c:4931
int r
Definition: cuts.c:4927
int t
Definition: cuts.c:4928
SCIP_Real * m
Definition: cuts.c:4921
SCIP_Real d2
Definition: cuts.c:4930
SCIP_Real mp
Definition: cuts.c:4932
SCIP_Real ml
Definition: cuts.c:4933
SCIP_Real d1
Definition: cuts.c:4929
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
int var_probindex
Definition: struct_lp.h:178
int rank
Definition: struct_lp.h:248
SCIP_Real rhs
Definition: struct_lp.h:205
int lppos
Definition: struct_lp.h:239
SCIP_Real * vals
Definition: struct_lp.h:229
unsigned int local
Definition: struct_lp.h:259
SCIP_Real lhs
Definition: struct_lp.h:204
SCIP_COL ** cols
Definition: struct_lp.h:227
unsigned int integral
Definition: struct_lp.h:258
SCIP_Real constant
Definition: struct_lp.h:203
int * cols_index
Definition: struct_lp.h:228
int len
Definition: struct_lp.h:235
SCIP_Real * transbinvarsolvals
Definition: cuts.c:4941
int * transvarcoefs
Definition: cuts.c:4940
SCIP_Real * transcontvarsolvals
Definition: cuts.c:4942
SCIP_Real * aggrcoefsbin
Definition: cuts.c:4948
int * origcontvars
Definition: cuts.c:4947
SCIP_Real transrhs
Definition: cuts.c:4945
int * origbinvars
Definition: cuts.c:4946
SCIP_Real * aggrconstants
Definition: cuts.c:4952
SCIP_Real * aggrcoefscont
Definition: cuts.c:4950
int ntransvars
Definition: cuts.c:4944
SCIP_Real * transvarvubcoefs
Definition: cuts.c:4943
data structures for LP management
SCIP main data structure.
datastructures for global SCIP settings
@ SCIP_BOUNDTYPE_UPPER
Definition: type_lp.h:57
@ SCIP_BOUNDTYPE_LOWER
Definition: type_lp.h:56
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
@ 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_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:63
@ SCIP_VARTYPE_CONTINUOUS
Definition: type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:62