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