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
86
91 else
93
94 if( ! ignoresol )
95 {
97 }
98 else
99 {
100 if( cutcoefs[i] > 0.0 )
101 {
103 }
104 else
105 {
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);
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]]);
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 {
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
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 {
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 {
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);
526 }
527 }
528 else
529 {
530 if( SCIPisInfinity(scip, -lb) )
531 return TRUE;
532 else
533 {
534 SCIPquadprecProdQD(val, val, lb);
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);
623 }
624 }
625 else
626 {
627 if( SCIPisInfinity(scip, -lb) )
628 return TRUE;
629 else
630 {
631 SCIPquadprecProdDD(quadprod, -val, lb);
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
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
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
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
713
714 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
715 {
717
718 if( SCIPisInfinity(scip, ub) )
719 return TRUE;
720 else
721 {
722 SCIPquadprecProdQD(delta, delta, ub);
724 }
725 }
726 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
727 {
729
730 if( SCIPisInfinity(scip, -lb) )
731 return TRUE;
732 else
733 {
734 SCIPquadprecProdQD(delta, delta, lb);
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
758
759 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
760 {
762
763 if( SCIPisInfinity(scip, ub) )
764 return TRUE;
765 else
766 {
767 SCIPquadprecProdQD(delta, delta, ub);
769 }
770 }
771 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
772 {
774
775 if( SCIPisInfinity(scip, -lb) )
776 return TRUE;
777 else
778 {
779 SCIPquadprecProdQD(delta, delta, lb);
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
813
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
829
830 if( QUAD_TO_DBL(val) < 0.0 )
831 {
833
834 if( SCIPisInfinity(scip, -lb) )
835 return SCIP_OKAY;
836
837 if( cutinds[i] < nintegralvars )
839 else
840 {
842 isintegral = FALSE;
843 }
844
845 SCIPquadprecProdQD(val, val, lb);
847 }
848 else
849 {
851
852 if( SCIPisInfinity(scip, ub) )
853 return SCIP_OKAY;
854
855 if( cutinds[i] < nintegralvars )
857 else
858 {
860 isintegral = FALSE;
861 }
862
863 SCIPquadprecProdQD(val, val, ub);
865 }
866 }
867
869
870 /* cut is redundant in activity bounds */
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
886
888
889 for( i = 0; i < *cutnnz; ++i )
890 {
891 SCIP_Real QUAD(val);
892
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
903
904 if( success )
905 {
906 /* if successful, apply the scaling */
908
910
911 for( i = 0; i < *cutnnz; )
912 {
913 SCIP_Real QUAD(val);
914 SCIP_Real intval;
915
917 SCIPquadprecProdQD(val, val, intscalar);
918
919 intval = SCIPround(scip, QUAD_TO_DBL(val));
920
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);
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);
939 --(*cutnnz);
940 cutinds[i] = cutinds[*cutnnz];
941 }
942 }
943
945
946 /* recompute the maximal activity after scaling to integral values */
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
958
959 if( QUAD_TO_DBL(val) < 0.0 )
960 {
962
964
965 SCIPquadprecProdQD(val, val, lb);
966
968 }
969 else
970 {
972
974
975 SCIPquadprecProdQD(val, val, ub);
976
978 }
979 }
980
982
983 assert(EPSISINT(maxact, 1e-4));
986
987 /* check again for redundancy */
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 */
1001
1004
1005 for( i = 0; i < *cutnnz; ++i )
1006 {
1007 SCIP_Real QUAD(val);
1008
1010 SCIPquadprecProdQD(val, val, equiscale);
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 */
1030
1031 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
1032 maxabsintval *= scale;
1033
1034 for( i = 0; i < *cutnnz; ++i )
1035 {
1036 SCIP_Real QUAD(val);
1037
1039 SCIPquadprecProdQD(val, val, scale);
1041 }
1042 }
1043
1044 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1046 return SCIP_OKAY;
1047
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
1062
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);
1069
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",
1091
1093
1095
1096 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
1097 {
1101 }
1102 else
1103 {
1104 QUAD_ASSIGN(coef, 0.0);
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);
1116
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",
1138
1140
1141 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
1142
1143 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
1144 {
1148 }
1149 else
1150 {
1151 QUAD_ASSIGN(coef, 0.0);
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
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 {
1213
1214 if( SCIPisInfinity(scip, -lb) )
1215 return SCIP_OKAY;
1216
1217 if( cutinds[i] < nintegralvars )
1218 maxabsintval = MAX(maxabsintval, -val);
1219 else
1220 {
1222 isintegral = FALSE;
1223 }
1224
1225 SCIPquadprecProdDD(quadprod, val, lb);
1227 }
1228 else
1229 {
1231
1232 if( SCIPisInfinity(scip, ub) )
1233 return SCIP_OKAY;
1234
1235 if( cutinds[i] < nintegralvars )
1237 else
1238 {
1240 isintegral = FALSE;
1241 }
1242
1243 SCIPquadprecProdDD(quadprod, val, ub);
1245 }
1246 }
1247
1249
1250 /* cut is redundant in activity bounds */
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
1266
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
1282
1283 if( success )
1284 {
1285 /* if successful, apply the scaling */
1287
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 {
1340
1341 maxabsintval = MAX(maxabsintval, -val);
1342
1343 SCIPquadprecProdDD(quadprod, val, lb);
1345 }
1346 else
1347 {
1349
1351
1352 SCIPquadprecProdDD(quadprod, val, ub);
1354 }
1355 }
1356
1358
1359 assert(EPSISINT(maxact, 1e-4));
1362
1363 /* check again for redundancy */
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 */
1377
1380
1381 for( i = 0; i < *cutnnz; ++i )
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 */
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 */
1410 return SCIP_OKAY;
1411
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
1428
1429 if( val < 0.0 && SCIPisLE(scip, maxact + val, QUAD_TO_DBL(*cutrhs)) )
1430 {
1431 SCIP_Real QUAD(coef);
1433
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,
1455
1457
1459
1460 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
1461 {
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);
1479
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",
1501
1503
1505
1506 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
1507 {
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
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 {
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
1589 }
1590 else
1591 {
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
1607 }
1608 }
1609
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
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
1634
1635 if( cutcoefs[i] < 0.0 && SCIPisLE(scip, maxact + cutcoefs[i], *cutrhs) )
1636 {
1637 SCIP_Real coef = (*cutrhs) - maxact;
1639
1640 coef = floor(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,
1654
1656
1657 assert(!SCIPisPositive(scip, coef));
1658
1659 ++(*nchgcoefs);
1660
1661 if( SCIPisNegative(scip, coef) )
1662 {
1665 cutcoefs[i] = coef;
1666 }
1667 else
1668 {
1669 --(*cutnnz);
1670 cutinds[i] = cutinds[*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);
1680
1681 coef = ceil(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),
1695
1697
1698 assert(!SCIPisNegative(scip, coef));
1699
1700 ++(*nchgcoefs);
1701
1702 if( SCIPisPositive(scip, coef) )
1703 {
1706 cutcoefs[i] = coef;
1707 }
1708 else
1709 {
1710 --(*cutnnz);
1711 cutinds[i] = cutinds[*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:
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
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);
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
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
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 )
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 )
2250 }
2251
2252 /* add right hand side, update rank and local flag */
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);
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
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]]);
2399 }
2400
2401 maxcoef /= scip->set->sepa_maxcoefratio;
2404
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);
2439 assert(success != NULL);
2440
2441 *success = FALSE;
2442
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
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));
2467 }
2468
2469 maxcoef /= scip->set->sepa_maxcoefratio;
2472
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);
2617
2619 *bestlbtype = -1;
2620
2621 if( allowlocal )
2622 {
2623 SCIP_Real loclb;
2624
2626 if( SCIPisGT(scip, loclb, *bestlb) )
2627 {
2628 *bestlb = loclb;
2629 *bestlbtype = -2;
2630 }
2631 }
2632
2633 *simplebound = *bestlb;
2634
2636 {
2637 SCIP_Real bestvlb;
2638 int bestvlbidx;
2639
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 */
2650 assert(vlbvars != NULL);
2653 {
2654 *bestlb = bestvlb;
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);
2678
2680 *bestubtype = -1;
2681
2682 if( allowlocal )
2683 {
2684 SCIP_Real locub;
2685
2687 if( SCIPisLT(scip, locub, *bestub) )
2688 {
2689 *bestub = locub;
2690 *bestubtype = -2;
2691 }
2692 }
2693
2694 *simplebound = *bestub;
2695
2697 {
2698 SCIP_Real bestvub;
2699 int bestvubidx;
2700
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 */
2711 assert(vubvars != NULL);
2714 {
2715 *bestub = bestvub;
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 {
2759
2760 /* user has explicitly specified a bound to be used */
2762 {
2763 /* user wants to use lower bound */
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 */
2782 k = boundsfortrans[v];
2783 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
2784 assert(vlbvars != NULL);
2785 assert(vlbcoefs != NULL);
2786 assert(vlbconsts != NULL);
2787
2789 }
2790
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 {
2800
2801 /* user wants to use upper bound */
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 */
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 */
2828 }
2829
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) */
2845
2846 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
2848
2849 /* check, if variable is free variable */
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 */
2863
2864 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
2866 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
2868 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
2870 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
2872 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
2874 else if( *bestubtype == -1 ) /* prefer global standard bounds */
2876 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
2877 {
2878 if( *bestlb - simplelb > simpleub - *bestub )
2880 else
2882 }
2883 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
2885 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
2887 else /* no decision yet? just use lower bound */
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
2898
2899 if( SCIPisInfinity(scip, - *bestlb) )
2901 else if( !SCIPisNegative(scip, *bestlb) )
2902 {
2903 if( SCIPisInfinity(scip, *bestub) )
2905 else if( SCIPisZero(scip, glblb) )
2907 else if( SCIPisLE(scip, distlb, distub) )
2909 else
2911 }
2912 else
2913 {
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
2943
2944 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
2945
2946 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
2947 if( boundtype < 0 )
2948 {
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 {
2967 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
2968 }
2969 else
2970 {
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]);
2986
2987 /* check if integral variable already exists in the row */
2989
2990 if( QUAD_HI(zcoef) == 0.0 )
2991 cutinds[(*nnz)++] = zidx;
2992
2993 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
2995
2997 assert(QUAD_HI(zcoef) != 0.0);
2998
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
3020
3021 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
3022
3023 /* must be a standard bound */
3024 assert( boundtype < 0 );
3025
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;
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);
3102
3105
3106 /* allocate temporary memory to store best bounds and bound types */
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
3122
3123 /* determine the best bounds for the continuous variables */
3125 {
3126 SCIP_CALL( determineBestBounds(scip, vars[cutinds[i]], sol, boundswitch, usevbds ? 2 : 0, allowlocal, fixintegralrhs,
3129
3130 if( *freevariable )
3131 goto TERMINATE;
3132 }
3133
3134 /* remember start of integer variables in the aggrrow */
3136
3137 /* perform bound substitution for continuous variables */
3138 for( i = 0; i < aggrrowintstart; ++i )
3139 {
3140 int v = cutinds[i];
3141
3143 {
3145
3146 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
3147 boundtype[i] = bestlbtypes[i];
3148 varsign[i] = +1;
3149
3151 }
3152 else
3153 {
3155
3156 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
3157 boundtype[i] = bestubtypes[i];
3158 varsign[i] = -1;
3159
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];
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,
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 */
3205 {
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
3214 }
3215 else
3216 {
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
3225 }
3226 }
3227
3228 if( fixintegralrhs )
3229 {
3230 SCIP_Real f0;
3231
3232 /* check if rhs is fractional */
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]);
3278
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 */
3310 {
3311 besti = i;
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);
3325
3327 QUAD_SCALE(coef, varsign[besti]);
3328
3329 /* switch the complementation of this variable */
3331 SCIPquadprecProdQQ(tmp, tmp, coef);
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 */
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
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
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
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 {
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
3488
3489 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
3492
3493 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
3494 {
3496 }
3497 else
3498 {
3499 SCIPquadprecSumQQ(tmp, fj, -f0);
3502 }
3504 }
3505
3506 /* remove zero cut coefficients from cut */
3508 {
3509 QUAD_ASSIGN(cutaj, 0.0);
3511 --*nnz;
3512 cutinds[i] = cutinds[*nnz];
3513 continue;
3514 }
3515
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 */
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 */
3587 {
3588 QUAD_ASSIGN(cutaj, 0.0);
3592 boundtype[i] = boundtype[ndelcontvars];
3593 ++ndelcontvars;
3594 continue;
3595 }
3596
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 {
3613 }
3614 else
3615 {
3619 }
3620 }
3621 else
3622 {
3623 /* upper bound was used */
3624 if( boundtype[i] == -1 )
3625 {
3629 }
3630 else
3631 {
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));
3658 }
3659 else
3660 {
3661 /* variable upper bound was used */
3662 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
3666 }
3669 assert(0 <= zidx && zidx < firstcontvar);
3670
3673
3676
3677 /* update sparsity pattern */
3678 if( QUAD_HI(zcoef) == 0.0 )
3679 cutinds[(*nnz)++] = zidx;
3680
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 {
3699 }
3700 else
3701 {
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);
3752 assert(cutinds != NULL);
3753 assert(nnz != NULL);
3754 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
3755
3758
3759 rows = SCIPgetLPRows(scip);
3760 for( i = 0; i < nrowinds; i++ )
3761 {
3762 SCIP_ROW* row;
3763 SCIP_Real ar;
3764 SCIP_Real 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 ar = slacksign[i] * scale * weights[i]; /*lint !e613*/
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 */
3794 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
3796 else
3797 {
3798 SCIPquadprecSumQQ(cutar, fr, -f0);
3801 }
3802 }
3803 else
3804 {
3805 /* slack variable is continuous:
3806 * a^_r = a~_r = 0 , if a'_r >= 0
3807 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
3808 */
3809 if( ar >= 0.0 )
3810 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
3811 else
3813 }
3814
3815 /* if the coefficient was reduced to zero, ignore the slack variable */
3817 continue;
3818
3819 /* depending on the slack's sign, we have
3820 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
3821 * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
3822 */
3823 SCIPquadprecProdQD(myprod, cutar, -slacksign[i]);
3824
3825 /* add the slack's definition multiplied with a^_j to the cut */
3827
3828 /* move slack's constant to the right hand side */
3829 if( slacksign[i] == +1 ) /*lint !e613*/
3830 {
3831 SCIP_Real QUAD(rowrhs);
3832
3833 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
3834 assert(!SCIPisInfinity(scip, row->rhs));
3835 QUAD_ASSIGN(rowrhs, row->rhs - row->constant);
3836 if( row->integral )
3837 {
3838 /* the right hand side was implicitly rounded down in row aggregation */
3840 }
3843 }
3844 else
3845 {
3846 SCIP_Real QUAD(rowlhs);
3847
3848 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
3849 assert(!SCIPisInfinity(scip, -row->lhs));
3850 QUAD_ASSIGN(rowlhs, row->lhs - row->constant);
3851 if( row->integral )
3852 {
3853 /* the left hand side was implicitly rounded up in row aggregation */
3855 }
3858 }
3859 }
3860
3861 /* relax rhs to zero, if it's very close to 0 */
3862 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
3863 QUAD_ASSIGN(*cutrhs, 0.0);
3864
3865 return SCIP_OKAY;
3866}
3867
3868/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
3869 * these rows cannot participate in an MIR cut.
3870 *
3871 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
3872 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
3873 *
3874 * @pre This method can be called if @p scip is in one of the following stages:
3875 * - \ref SCIP_STAGE_SOLVING
3876 *
3877 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
3878 */
3880 SCIP* scip, /**< SCIP data structure */
3881 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
3882 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
3883 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
3884 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
3885 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
3886 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
3887 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
3888 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
3889 * NULL for using closest bound for all variables */
3890 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
3891 * NULL for using closest bound for all variables */
3892 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
3893 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
3894 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
3895 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
3896 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
3897 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
3898 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
3899 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
3900 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
3901 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
3902 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
3903 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
3904 )
3905{
3906 int i;
3907 int nvars;
3908 int tmpnnz;
3909 int* varsign;
3910 int* boundtype;
3911 int* tmpinds;
3912 SCIP_Real* tmpcoefs;
3913
3914 SCIP_Real QUAD(rhs);
3915 SCIP_Real QUAD(downrhs);
3916 SCIP_Real QUAD(f0);
3917 SCIP_Bool freevariable;
3918 SCIP_Bool localbdsused;
3919 SCIP_Bool tmpislocal;
3920
3921 assert(aggrrow != NULL);
3922 assert(SCIPisPositive(scip, scale));
3923 assert(success != NULL);
3924
3925 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
3926
3927 *success = FALSE;
3928
3929 /* allocate temporary memory */
3932 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
3935
3936 /* initialize cut with aggregation */
3937 tmpnnz = aggrrow->nnz;
3938 tmpislocal = aggrrow->local;
3939
3940 SCIPquadprecProdQD(rhs, aggrrow->rhs, scale);
3941
3942 if( tmpnnz > 0 )
3943 {
3945
3946 for( i = 0; i < tmpnnz; ++i )
3947 {
3948 SCIP_Real QUAD(coef);
3949 int k = aggrrow->inds[i];
3950
3951 QUAD_ARRAY_LOAD(coef, aggrrow->vals, k);
3952
3953 SCIPquadprecProdQD(coef, coef, scale);
3954
3955 QUAD_ARRAY_STORE(tmpcoefs, k, coef);
3956
3957 assert(QUAD_HI(coef) != 0.0);
3958 }
3959
3960 /* Transform equation a*x == b, lb <= x <= ub into standard form
3961 * a'*x' == b, 0 <= x' <= ub'.
3962 *
3963 * Transform variables (lb or ub):
3964 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
3965 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
3966 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
3967 *
3968 * Transform variables (vlb or vub):
3969 * 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.
3970 * 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.
3971 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
3972 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
3973 * a_{zu_j} := a_{zu_j} + a_j * bu_j
3974 */
3975 SCIP_CALL( cutsTransformMIR(scip, sol, boundswitch, usevbds, allowlocal, fixintegralrhs, FALSE,
3977 assert(allowlocal || !localbdsused);
3979
3980 if( freevariable )
3981 goto TERMINATE;
3982
3983 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
3985 }
3986
3987 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
3988 * a~*x' <= down(b)
3989 * integers : a~_j = down(a'_j) , if f_j <= f_0
3990 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
3991 * continuous: a~_j = 0 , if a'_j >= 0
3992 * a~_j = a'_j/(1 - f0) , if a'_j < 0
3993 *
3994 * Transform inequality back to a^*x <= rhs:
3995 *
3996 * (lb or ub):
3997 * 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
3998 * 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
3999 * and move the constant terms
4000 * -a~_j * lb_j == -a^_j * lb_j, or
4001 * a~_j * ub_j == -a^_j * ub_j
4002 * to the rhs.
4003 *
4004 * (vlb or vub):
4005 * 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)
4006 * 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)
4007 * move the constant terms
4008 * -a~_j * dl_j == -a^_j * dl_j, or
4009 * a~_j * du_j == -a^_j * du_j
4010 * to the rhs, and update the VB variable coefficients:
4011 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
4012 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
4013 */
4014 SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
4015
4016 SCIPquadprecSumQQ(f0, rhs, -downrhs);
4017
4018 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
4019 goto TERMINATE;
4020
4021 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
4022 * If this gives a scalar that is very big, we better do not generate this cut.
4023 */
4024 if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
4025 goto TERMINATE;
4026
4027 /* renormalize f0 value */
4028 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
4029
4030 QUAD_ASSIGN_Q(rhs, downrhs);
4031
4032 if( tmpnnz > 0 )
4033 {
4034 SCIP_CALL( cutsRoundMIR(scip, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, varsign, boundtype, QUAD(f0)) );
4035
4036 SCIPdebugMsg(scip, "After MIR rounding:\n");
4038 }
4039
4040 /* substitute aggregated slack variables:
4041 *
4042 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
4043 * variable only appears in its own row:
4044 * a'_r = scale * weight[r] * slacksign[r].
4045 *
4046 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
4047 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
4048 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
4049 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
4050 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
4051 *
4052 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
4053 */
4054 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
4055 aggrrow->nrows, scale, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, QUAD(f0)) );
4056
4057 SCIPdebugMsg(scip, "After slack substitution:\n");
4059
4060 if( postprocess )
4061 {
4062 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
4063 * prevent numerical rounding errors
4064 */
4066 }
4067 else
4068 {
4070 }
4071
4072 SCIPdebugMsg(scip, "After post processing:\n");
4074
4075 if( *success )
4076 {
4078
4080 {
4082 *cutnnz = tmpnnz;
4083 *cutrhs = QUAD_TO_DBL(rhs);
4085
4086 /* clean tmpcoefs and go back to double precision */
4087 for( i = 0; i < *cutnnz; ++i )
4088 {
4089 SCIP_Real QUAD(coef);
4090 int j = cutinds[i];
4091
4092 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
4093
4094 cutcoefs[i] = QUAD_TO_DBL(coef);
4095 QUAD_ASSIGN(coef, 0.0);
4096 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
4097 }
4098
4099 if( cutefficacy != NULL )
4101
4102 if( cutrank != NULL )
4103 *cutrank = aggrrow->rank + 1;
4104 }
4105 else
4106 {
4107 *success = FALSE;
4108 }
4109 }
4110
4111 TERMINATE:
4112 if( !(*success) )
4113 {
4114 SCIP_Real QUAD(tmp);
4115
4116 QUAD_ASSIGN(tmp, 0.0);
4117 for( i = 0; i < tmpnnz; ++i )
4118 {
4120 }
4121 }
4122
4123 /* free temporary memory */
4126 SCIPfreeBufferArray(scip, &boundtype);
4128
4129 return SCIP_OKAY;
4130}
4131
4132/** compute the efficacy of the MIR cut for the given values without computing the cut.
4133 * This is used for the CMIR cut generation heuristic.
4134 */
4135static
4137 SCIP* scip, /**< SCIP datastructure */
4138 SCIP_Real*RESTRICT coefs, /**< array with coefficients in row */
4139 SCIP_Real*RESTRICT solvals, /**< solution values of variables in the row */
4140 SCIP_Real rhs, /**< right hand side of MIR cut */
4141 SCIP_Real contactivity, /**< aggregated activity of continuous variables in the row */
4142 SCIP_Real contsqrnorm, /**< squared norm of continuous variables */
4143 SCIP_Real delta, /**< delta value to compute the violation for */
4144 int nvars, /**< number of variables in the row, i.e. the size of coefs and solvals arrays */
4145 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4146 SCIP_Real maxfrac /**< maximal fractionality of rhs to produce MIR cut for */
4147 )
4148{
4149 int i;
4150 SCIP_Real f0pluseps;
4151 SCIP_Real f0;
4152 SCIP_Real onedivoneminusf0;
4153 SCIP_Real scale;
4154 SCIP_Real downrhs;
4155 SCIP_Real norm;
4156 SCIP_Real contscale;
4157
4158 scale = 1.0 / delta;
4159 rhs *= scale;
4160 downrhs = SCIPfloor(scip, rhs);
4161 f0 = rhs - downrhs;
4162
4164 return 0.0;
4165
4166 onedivoneminusf0 = 1.0 / (1.0 - f0);
4167
4168 contscale = scale * onedivoneminusf0;
4169
4170 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
4171 * If this gives a scalar that is very big, we better do not generate this cut.
4172 */
4173 if( contscale > MAXCMIRSCALE )
4174 return 0.0;
4175
4176 rhs = downrhs;
4177 rhs -= contscale * contactivity;
4178 norm = SQR(contscale) * contsqrnorm;
4179
4180 assert(!SCIPisFeasZero(scip, f0));
4181 assert(!SCIPisFeasZero(scip, 1.0 - f0));
4182
4183 f0pluseps = f0 + SCIPepsilon(scip);
4184
4185 for( i = 0; i < nvars; ++i )
4186 {
4187 SCIP_Real floorai = floor(scale * coefs[i]);
4188 SCIP_Real fi = (scale * coefs[i]) - floorai;
4189
4190 if( fi > f0pluseps )
4191 floorai += (fi - f0) * onedivoneminusf0;
4192
4193 rhs -= solvals[i] * floorai;
4194 norm += SQR(floorai);
4195 }
4196
4197 norm = sqrt(norm);
4198
4199 return - rhs / MAX(norm, 1e-6);
4200}
4201
4202/** calculates an MIR cut out of an aggregation of LP rows
4203 *
4204 * Given the aggregation, it is transformed to a mixed knapsack set via complementation (using bounds or variable bounds)
4205 * Then, different scalings of the mkset are used to generate a MIR and the best is chosen.
4206 * One of the steps of the MIR is to round the coefficients of the integer variables down,
4207 * so one would prefer to have integer coefficients for integer variables which are far away from their bounds in the
4208 * mkset.
4209 *
4210 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4211 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4212 *
4213 * @pre This method can be called if @p scip is in one of the following stages:
4214 * - \ref SCIP_STAGE_SOLVING
4215 *
4216 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
4217 */
4219 SCIP* scip, /**< SCIP data structure */
4220 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4221 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
4222 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
4223 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
4224 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4225 int maxtestdelta, /**< maximum number of deltas to test */
4226 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
4227 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
4228 * NULL for using closest bound for all variables */
4229 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
4230 * NULL for using closest bound for all variables */
4231 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4232 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
4233 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
4234 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
4235 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
4236 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
4237 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
4238 SCIP_Real* cutefficacy, /**< pointer to store efficacy of best cut; only cuts that are strictly better than the value of
4239 * this efficacy on input to this function are returned */
4240 int* cutrank, /**< pointer to return rank of generated cut (or NULL) */
4241 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
4242 SCIP_Bool* success /**< pointer to store whether a valid and efficacious cut was returned */
4243 )
4244{
4245 int i;
4246 int firstcontvar;
4247 int nvars;
4248 int intstart;
4249 int ntmpcoefs;
4250 int* varsign;
4251 int* boundtype;
4252 int* mksetinds;
4253 SCIP_Real* mksetcoefs;
4254 SCIP_Real QUAD(mksetrhs);
4255 int mksetnnz;
4256 SCIP_Real* bounddist;
4257 int* bounddistpos;
4258 int nbounddist;
4259 SCIP_Real* tmpcoefs;
4260 SCIP_Real* tmpvalues;
4261 SCIP_Real* deltacands;
4262 int ndeltacands;
4263 SCIP_Real bestdelta;
4264 SCIP_Real bestefficacy;
4265 SCIP_Real maxabsmksetcoef;
4266 SCIP_VAR** vars;
4267 SCIP_Bool freevariable;
4268 SCIP_Bool localbdsused;
4269 SCIP_Real contactivity;
4270 SCIP_Real contsqrnorm;
4271
4272 assert(aggrrow != NULL);
4273 assert(aggrrow->nrows + aggrrow->nnz >= 1);
4274 assert(success != NULL);
4275
4276 *success = FALSE;
4280
4281 /* allocate temporary memory */
4283 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
4288 SCIP_CALL( SCIPallocBufferArray(scip, &deltacands, aggrrow->nnz + 6) );
4289
4290 /* we only compute bound distance for integer variables; we allocate an array of length aggrrow->nnz to store this, since
4291 * this is the largest number of integer variables. (in contrast to the number of total variables which can be 2 *
4292 * aggrrow->nnz variables: if all are continuous and we use variable bounds to completement, we introduce aggrrow->nnz
4293 * extra vars)
4294 */
4295 SCIP_CALL( SCIPallocBufferArray(scip, &bounddist, aggrrow->nnz) );
4297
4298 /* initialize mkset with aggregation */
4299 mksetnnz = aggrrow->nnz;
4300 QUAD_ASSIGN_Q(mksetrhs, aggrrow->rhs);
4301
4303
4304 for( i = 0; i < mksetnnz; ++i )
4305 {
4306 int j = mksetinds[i];
4307 SCIP_Real QUAD(coef);
4308 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
4310 assert(QUAD_HI(coef) != 0.0);
4311 }
4312
4313 *cutislocal = aggrrow->local;
4314
4315 /* Transform equation a*x == b, lb <= x <= ub into standard form
4316 * a'*x' == b, 0 <= x' <= ub'.
4317 *
4318 * Transform variables (lb or ub):
4319 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
4320 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
4321 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
4322 *
4323 * Transform variables (vlb or vub):
4324 * 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.
4325 * 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.
4326 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
4327 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
4328 * a_{zu_j} := a_{zu_j} + a_j * bu_j
4329 */
4332
4333 assert(allowlocal || !localbdsused);
4334
4335 if( freevariable )
4336 goto TERMINATE;
4337
4338 SCIPdebugMsg(scip, "transformed aggrrow row:\n");
4340
4341 /* found positions of integral variables that are strictly between their bounds */
4342 maxabsmksetcoef = -1.0;
4343 nbounddist = 0;
4344
4345 for( i = mksetnnz - 1; i >= 0 && mksetinds[i] < firstcontvar; --i )
4346 {
4348 SCIP_Real primsol = SCIPgetSolVal(scip, sol, var);
4349 SCIP_Real lb = SCIPvarGetLbLocal(var);
4350 SCIP_Real ub = SCIPvarGetUbLocal(var);
4351 SCIP_Real QUAD(coef);
4352
4354
4355 if( SCIPisEQ(scip, primsol, lb) || SCIPisEQ(scip, primsol, ub) )
4356 continue;
4357
4358 bounddist[nbounddist] = MIN(ub - primsol, primsol - lb);
4361 ++nbounddist;
4362 }
4363
4364 /* no fractional variable; so abort here */
4365 if( nbounddist == 0 )
4366 goto TERMINATE;
4367
4368 intstart = i + 1;
4370
4372
4373 {
4374 SCIP_Real intscale;
4375 SCIP_Bool intscalesuccess;
4376
4378
4379 if( intscalesuccess )
4380 {
4381 SCIP_Real intf0;
4382 SCIP_Real intscalerhs;
4383 SCIP_Real delta;
4384
4386 delta = 1.0 / intscale;
4388
4389 if( ! SCIPisFeasIntegral(scip, intf0) )
4390 {
4392 {
4393 intscale *= ceil(MAX(minfrac, (1.0 - maxfrac)) / MIN(intf0, (1.0 - intf0)));
4395 delta = 1.0 / intscale;
4397 }
4398
4399 if( intf0 >= minfrac && intf0 <= maxfrac )
4400 {
4401 if( ! SCIPisEQ(scip, delta, 1.0) )
4402 deltacands[ndeltacands++] = delta;
4403
4404 if( intf0 < maxfrac )
4405 {
4406 SCIP_Real delta2;
4407
4408 delta2 = 1.0 / (intscale * floor(maxfrac / intf0));
4409
4410 if( ! SCIPisEQ(scip, delta, delta2) && ! SCIPisEQ(scip, delta2, 1.0) )
4412 }
4413 }
4414 }
4415 }
4416 }
4417
4418 for( i = 0; i < nbounddist; ++i )
4419 {
4420 SCIP_Real absmksetcoef;
4421
4424
4426 }
4427
4428 /* also test 1.0 and maxabsmksetcoef + 1.0 as last delta values */
4429 if( maxabsmksetcoef != -1.0 )
4431
4432 deltacands[ndeltacands++] = 1.0;
4433
4434 maxtestdelta = MIN(ndeltacands, maxtestdelta);
4435
4436 /* For each delta
4437 * Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
4438 * a~*x' <= down(b)
4439 * integers : a~_j = down(a'_j) , if f_j <= f_0
4440 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
4441 * continuous: a~_j = 0 , if a'_j >= 0
4442 * a~_j = a'_j/(1 - f0) , if a'_j < 0
4443 *
4444 * Transform inequality back to a^*x <= rhs:
4445 *
4446 * (lb or ub):
4447 * 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
4448 * 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
4449 * and move the constant terms
4450 * -a~_j * lb_j == -a^_j * lb_j, or
4451 * a~_j * ub_j == -a^_j * ub_j
4452 * to the rhs.
4453 *
4454 * (vlb or vub):
4455 * 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)
4456 * 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)
4457 * move the constant terms
4458 * -a~_j * dl_j == -a^_j * dl_j, or
4459 * a~_j * du_j == -a^_j * du_j
4460 * to the rhs, and update the VB variable coefficients:
4461 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
4462 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
4463 */
4464
4465 ntmpcoefs = 0;
4466 for( i = intstart; i < mksetnnz; ++i )
4467 {
4468 SCIP_VAR* var;
4469 SCIP_Real solval;
4470 SCIP_Real QUAD(coef);
4471
4472 var = vars[mksetinds[i]];
4473
4474 /* get the soltion value of the continuous variable */
4475 solval = SCIPgetSolVal(scip, sol, var);
4476
4477 /* now compute the solution value in the transform space considering complementation */
4478 if( boundtype[i] == -1 )
4479 {
4480 /* variable was complemented with global (simple) bound */
4481 if( varsign[i] == -1 )
4482 solval = SCIPvarGetUbGlobal(var) - solval;
4483 else
4484 solval = solval - SCIPvarGetLbGlobal(var);
4485 }
4486 else
4487 {
4488 assert(boundtype[i] == -2);
4489
4490 /* variable was complemented with local (simple) bound */
4491 if( varsign[i] == -1 )
4492 solval = SCIPvarGetUbLocal(var) - solval;
4493 else
4494 solval = solval - SCIPvarGetLbLocal(var);
4495 }
4496
4497 tmpvalues[ntmpcoefs] = solval;
4500 ++ntmpcoefs;
4501 }
4502
4504
4505 contactivity = 0.0;
4506 contsqrnorm = 0.0;
4507 for( i = 0; i < intstart; ++i )
4508 {
4509 SCIP_Real solval;
4510 SCIP_Real QUAD(mksetcoef);
4511
4513
4514 if( varsign[i] * QUAD_TO_DBL(mksetcoef) >= 0.0 )
4515 continue;
4516
4517 /* get the soltion value of the continuous variable */
4518 solval = SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
4519
4520 /* now compute the solution value in the transform space considering complementation */
4521 switch( boundtype[i] )
4522 {
4523 case -1:
4524 /* variable was complemented with global (simple) bound */
4525 if( varsign[i] == -1 )
4526 solval = SCIPvarGetUbGlobal(vars[mksetinds[i]]) - solval;
4527 else
4528 solval = solval - SCIPvarGetLbGlobal(vars[mksetinds[i]]);
4529 break;
4530 case -2:
4531 /* variable was complemented with local (simple) bound */
4532 if( varsign[i] == -1 )
4533 solval = SCIPvarGetUbLocal(vars[mksetinds[i]]) - solval;
4534 else
4535 solval = solval - SCIPvarGetLbLocal(vars[mksetinds[i]]);
4536 break;
4537 default:
4538 /* variable was complemented with a variable bound */
4539 if( varsign[i] == -1 )
4540 {
4541 SCIP_Real coef;
4542 SCIP_Real constant;
4543 SCIP_Real vbdsolval;
4544
4545 coef = SCIPvarGetVubCoefs(vars[mksetinds[i]])[boundtype[i]];
4546 constant = SCIPvarGetVubConstants(vars[mksetinds[i]])[boundtype[i]];
4548
4549 solval = (coef * vbdsolval + constant) - solval;
4550 }
4551 else
4552 {
4553 SCIP_Real coef;
4554 SCIP_Real constant;
4555 SCIP_Real vbdsolval;
4556
4557 coef = SCIPvarGetVlbCoefs(vars[mksetinds[i]])[boundtype[i]];
4558 constant = SCIPvarGetVlbConstants(vars[mksetinds[i]])[boundtype[i]];
4560
4561 solval = solval - (coef * vbdsolval + constant);
4562 }
4563 }
4564
4565 contactivity += solval * (QUAD_TO_DBL(mksetcoef) * varsign[i]);
4567 }
4568
4569 {
4570 SCIP_ROW** rows;
4571
4572 rows = SCIPgetLPRows(scip);
4573
4574 for( i = 0; i < aggrrow->nrows; ++i )
4575 {
4576 SCIP_ROW* row;
4577 SCIP_Real slackval;
4578
4579 row = rows[aggrrow->rowsinds[i]];
4580
4581 if( (aggrrow->rowweights[i] * aggrrow->slacksign[i]) >= 0.0 && !row->integral )
4582 continue;
4583
4584 /* compute solution value of slack variable */
4586
4587 if( aggrrow->slacksign[i] == +1 )
4588 {
4589 /* right hand side */
4590 assert(!SCIPisInfinity(scip, row->rhs));
4591
4592 slackval = row->rhs - slackval;
4593 }
4594 else
4595 {
4596 /* left hand side */
4597 assert(aggrrow->slacksign[i] == -1);
4598 assert(!SCIPisInfinity(scip, -row->lhs));
4599
4600 slackval = slackval - row->lhs;
4601 }
4602
4603 if( row->integral )
4604 {
4605 /* if row is integral add variable to tmp arrays */
4607 tmpcoefs[ntmpcoefs] = aggrrow->rowweights[i] * aggrrow->slacksign[i];
4608 ++ntmpcoefs;
4609 }
4610 else
4611 {
4612 SCIP_Real slackcoeff = (aggrrow->rowweights[i] * aggrrow->slacksign[i]);
4613
4614 /* otherwise add it to continuous activity */
4617 }
4618 }
4619 }
4620
4621 /* try all candidates for delta and remember best */
4623 bestefficacy = -SCIPinfinity(scip);
4624
4625 for( i = 0; i < maxtestdelta; ++i )
4626 {
4627 int j;
4628 SCIP_Real efficacy;
4629
4630 /* check if we have seen this value of delta before */
4631 SCIP_Bool deltaseenbefore = FALSE;
4632 for( j = 0; j < i; ++j )
4633 {
4635 {
4637 break;
4638 }
4639 }
4640
4641 /* skip this delta value and allow one more delta value if available */
4642 if( deltaseenbefore )
4643 {
4644 maxtestdelta = MIN(maxtestdelta + 1, ndeltacands);
4645 continue;
4646 }
4647
4649
4650 if( efficacy > bestefficacy )
4651 {
4652 bestefficacy = efficacy;
4654 }
4655 }
4656
4657 /* no delta was found that yielded any cut */
4658 if( bestdelta == SCIP_INVALID ) /*lint !e777*/
4659 goto TERMINATE;
4660
4661 /* try bestdelta divided by 2, 4 and 8 */
4662 {
4663 SCIP_Real basedelta = bestdelta;
4664 for( i = 2; i <= 8 ; i *= 2 )
4665 {
4666 SCIP_Real efficacy;
4667 SCIP_Real delta;
4668
4669 delta = basedelta / i;
4670
4672
4673 if( efficacy > bestefficacy )
4674 {
4675 bestefficacy = efficacy;
4676 bestdelta = delta;
4677 }
4678 }
4679 }
4680
4681 /* try to improve efficacy by switching complementation of integral variables that are not at their bounds
4682 * in order of non-increasing bound distance
4683 */
4684 for( i = 0; i < nbounddist; ++i )
4685 {
4686 int k;
4687 SCIP_Real newefficacy;
4688 SCIP_Real QUAD(newrhs);
4689 SCIP_Real QUAD(quadprod);
4690 SCIP_Real bestlb;
4691 SCIP_Real bestub;
4692 SCIP_Real oldsolval;
4693 SCIP_Real simplebnd;
4694 int bestlbtype;
4695 int bestubtype;
4696
4697 k = bounddistpos[i];
4698
4699 SCIP_CALL( findBestLb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestlb, &simplebnd, &bestlbtype) );
4700
4701 if( SCIPisInfinity(scip, -bestlb) )
4702 continue;
4703
4704 SCIP_CALL( findBestUb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestub, &simplebnd, &bestubtype) );
4705
4706 if( SCIPisInfinity(scip, bestub) )
4707 continue;
4708
4709 /* switch the complementation of this variable */
4710#ifndef NDEBUG
4711 {
4712 SCIP_Real QUAD(coef);
4715 }
4716#endif
4717
4718 /* compute this: newrhs = mksetrhs + tmpcoefs[k - intstart] * (bestlb - bestub); */
4722
4725
4726 /* compute new violation */
4728
4729 /* check if violaton was increased */
4730 if( newefficacy > bestefficacy )
4731 {
4732 /* keep change of complementation */
4733 bestefficacy = newefficacy;
4735
4736 if( varsign[k] == +1 )
4737 {
4738 /* switch to upper bound */
4739 assert(bestubtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4740 boundtype[k] = bestubtype;
4741 varsign[k] = -1;
4742 }
4743 else
4744 {
4745 /* switch to lower bound */
4746 assert(bestlbtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4747 boundtype[k] = bestlbtype;
4748 varsign[k] = +1;
4749 }
4750
4751 localbdsused = localbdsused || (boundtype[k] == -2);
4752 }
4753 else
4754 {
4755 /* undo the change of the complementation */
4758 }
4759 } /*lint !e438*/
4760
4761 if( bestefficacy > 0.0 )
4762 {
4763 SCIP_Real mirefficacy;
4764 SCIP_Real QUAD(downrhs);
4765 SCIP_Real QUAD(f0);
4766 SCIP_Real scale;
4767
4768 scale = 1.0 / bestdelta;
4770
4773
4774 /* renormaliize f0 value */
4775 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
4776
4777 for( i = 0; i < mksetnnz; ++i )
4778 {
4779 SCIP_Real QUAD(coef);
4780
4782 SCIPquadprecProdQD(coef, coef, scale);
4784 }
4785 SCIPdebugMsg(scip, "applied best scale (=%.13g):\n", scale);
4787
4789
4791
4792 SCIPdebugMsg(scip, "rounded MIR cut:\n");
4794
4795 /* substitute aggregated slack variables:
4796 *
4797 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
4798 * variable only appears in its own row:
4799 * a'_r = scale * weight[r] * slacksign[r].
4800 *
4801 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
4802 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
4803 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
4804 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
4805 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
4806 *
4807 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
4808 */
4809 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
4810 aggrrow->nrows, scale, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, QUAD(f0)) );
4811
4812 SCIPdebugMsg(scip, "substituted slacks in MIR cut:\n");
4814
4815#ifndef NDEBUG
4816 {
4817 SCIP_Real efficacy = -QUAD_TO_DBL(mksetrhs);
4818 for( i = 0; i < mksetnnz; ++i )
4819 {
4820 SCIP_Real QUAD(coef);
4823 }
4824
4825 if( !EPSZ(SCIPrelDiff(efficacy, bestefficacy), 1e-4) )
4826 {
4827 SCIPdebugMsg(scip, "efficacy of cmir cut is different than expected efficacy: %f != %f\n", efficacy, bestefficacy);
4828 }
4829 }
4830#endif
4831
4833
4834 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
4835 * prevent numerical rounding errors
4836 */
4837 if( postprocess )
4838 {
4840 }
4841 else
4842 {
4844 }
4845
4846 SCIPdebugMsg(scip, "post-processed cut (success = %s):\n", *success ? "TRUE" : "FALSE");
4848
4849 if( *success )
4850 {
4852
4854 {
4856 for( i = 0; i < mksetnnz; ++i )
4857 {
4858 SCIP_Real QUAD(coef);
4859 int j = cutinds[i];
4860
4862
4863 cutcoefs[i] = QUAD_TO_DBL(coef);
4864 QUAD_ASSIGN(coef, 0.0);
4866 }
4867 *cutnnz = mksetnnz;
4870 if( cutrank != NULL )
4871 *cutrank = aggrrow->rank + 1;
4873 }
4874 else
4875 *success = FALSE;
4876 }
4877 }
4878
4879 TERMINATE:
4880 /* if we aborted early we need to clean the mksetcoefs */
4881 if( !(*success) )
4882 {
4883 SCIP_Real QUAD(tmp);
4884 QUAD_ASSIGN(tmp, 0.0);
4885
4886 for( i = 0; i < mksetnnz; ++i )
4887 {
4889 }
4890 }
4891
4892 /* free temporary memory */
4894 SCIPfreeBufferArray(scip, &bounddist);
4900 SCIPfreeBufferArray(scip, &boundtype);
4902
4903 return SCIP_OKAY;
4904}
4905
4906/* =========================================== flow cover =========================================== */
4907
4908#define NO_EXACT_KNAPSACK
4909
4910#ifndef NO_EXACT_KNAPSACK
4911#define MAXDNOM 1000LL
4912#define MINDELTA 1e-03
4913#define MAXDELTA 1e-09
4914#define MAXSCALE 1000.0
4915#define MAXDYNPROGSPACE 1000000
4916#endif
4917
4918#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for snf relaxation */
4919#define MAXBOUND 1e+10 /**< maximal value of normal bounds used for snf relaxation */
4920
4921/** structure that contains all data required to perform the sequence independent lifting
4922 */
4923typedef
4924struct LiftingData
4925{
4926 SCIP_Real* M; /**< \f$ M_0 := 0.0 \f$ and \f$ M_i := M_i-1 + m_i \f$ */
4927 SCIP_Real* m; /**< non-increasing array of variable upper bound coefficients
4928 * for all variables in \f$ C^{++} \f$ and \f$ L^- \f$,
4929 * where \f$ C = C^+ \cup C^- \f$ is the flowcover and
4930 * \f$ C^{++} := \{ j \in C^+ \mid u_j > \lambda \} \f$
4931 * \f$ L^- := \{ j \in (N^- \setminus C^-) \mid u_j > \lambda \} \f$
4932 */
4933 int r; /**< size of array m */
4934 int t; /**< index of smallest value in m that comes from a variable in \f$ C^{++} \f$ */
4935 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$ */
4936 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$ */
4937 SCIP_Real lambda; /**< excess of the flowcover */
4938 SCIP_Real mp; /**< smallest variable bound coefficient of variable in \f$ C^{++} (min_{j \in C++} u_j) \f$ */
4939 SCIP_Real ml; /**< \f$ ml := min(\lambda, \sum_{j \in C^+ \setminus C^{++}} u_j) \f$ */
4941
4942/** structure that contains all the data that defines the single-node-flow relaxation of an aggregation row */
4943typedef
4944struct SNF_Relaxation
4945{
4946 int* transvarcoefs; /**< coefficients of all vars in relaxed set */
4947 SCIP_Real* transbinvarsolvals; /**< sol val of bin var in vub of all vars in relaxed set */
4948 SCIP_Real* transcontvarsolvals;/**< sol val of all real vars in relaxed set */
4949 SCIP_Real* transvarvubcoefs; /**< coefficient in vub of all vars in relaxed set */
4950 int ntransvars; /**< number of vars in relaxed set */
4951 SCIP_Real transrhs; /**< rhs in relaxed set */
4952 int* origbinvars; /**< associated original binary var for all vars in relaxed set */
4953 int* origcontvars; /**< associated original continuous var for all vars in relaxed set */
4954 SCIP_Real* aggrcoefsbin; /**< aggregation coefficient of the original binary var used to define the
4955 * continuous variable in the relaxed set */
4956 SCIP_Real* aggrcoefscont; /**< aggregation coefficient of the original continuous var used to define the
4957 * continuous variable in the relaxed set */
4958 SCIP_Real* aggrconstants; /**< aggregation constant used to define the continuous variable in the relaxed set */
4960
4961/** get solution value and index of variable lower bound (with binary variable) which is closest to the current LP
4962 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
4963 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
4964 * given variable
4965 */
4966static
4968 SCIP* scip, /**< SCIP data structure */
4969 SCIP_VAR* var, /**< given active problem variable */
4970 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
4971 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
4972 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
4973 * was not used (0) or was not used but is contained in the row (-1)
4974 */
4975 SCIP_Real bestsub, /**< closest simple upper bound of given variable */
4976 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
4977 SCIP_Real* closestvlb, /**< pointer to store the LP sol value of the closest variable lower bound */
4978 int* closestvlbidx /**< pointer to store the index of the closest vlb; -1 if no vlb was found */
4979 )
4980{
4981 int nvlbs;
4982 int nbinvars;
4983
4984 assert(scip != NULL);
4985 assert(var != NULL);
4989 assert(rowcoefs != NULL);
4992 assert(closestvlbidx != NULL);
4993
4996
4997 *closestvlbidx = -1;
4999 if( nvlbs > 0 )
5000 {
5001 SCIP_VAR** vlbvars;
5002 SCIP_Real* vlbcoefs;
5003 SCIP_Real* vlbconsts;
5004 int i;
5005
5009
5010 for( i = 0; i < nvlbs; i++ )
5011 {
5012 SCIP_Real rowcoefbinvar;
5013 SCIP_Real val1;
5014 SCIP_Real val2;
5015 SCIP_Real vlbsol;
5016 SCIP_Real rowcoefsign;
5017 int probidxbinvar;
5018
5019 if( bestsub > vlbconsts[i] )
5020 continue;
5021
5022 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
5023 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
5024 */
5025 if( REALABS(vlbcoefs[i]) > MAXABSVBCOEF )
5026 continue;
5027
5028 /* use only variable lower bounds l~_i * x_i + d_i with x_i binary which are active */
5030
5031 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
5032 * ensures that the problem index is between 0 and nbinvars - 1
5033 */
5034 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
5035 continue;
5036
5038
5039 /* check if current variable lower bound l~_i * x_i + d_i imposed on y_j meets the following criteria:
5040 * (let a_j = coefficient of y_j in current row,
5041 * u_j = closest simple upper bound imposed on y_j,
5042 * c_i = coefficient of x_i in current row)
5043 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k yet
5044 * if a_j > 0:
5045 * 1. u_j <= d_i
5046 * 2. a_j ( u_j - d_i ) + c_i <= 0
5047 * 3. a_j l~_i + c_i <= 0
5048 * if a_j < 0:
5049 * 1. u_j <= d_i
5050 * 2. a_j ( u_j - d_i ) + c_i >= 0
5051 * 3. a_j l~_i + c_i >= 0
5052 */
5053
5054 /* has already been used in the SNF relaxation */
5055 if( binvarused[probidxbinvar] == 1 )
5056 continue;
5057
5058 /* get the row coefficient */
5059 {
5060 SCIP_Real QUAD(tmp);
5063 }
5065
5067
5068 /* variable lower bound does not meet criteria */
5069 if( val2 > 0.0 || SCIPisInfinity(scip, -val2) )
5070 continue;
5071
5073
5074 /* variable lower bound does not meet criteria */
5075 if( val1 > 0.0 )
5076 continue;
5077
5079 if( vlbsol > *closestvlb )
5080 {
5081 *closestvlb = vlbsol;
5082 *closestvlbidx = i;
5083 }
5084 assert(*closestvlbidx >= 0);
5085 }
5086 }
5087
5088 return SCIP_OKAY;
5089}
5090
5091/** get LP solution value and index of variable upper bound (with binary variable) which is closest to the current LP
5092 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
5093 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
5094 * given variable
5095 */
5096static
5098 SCIP* scip, /**< SCIP data structure */
5099 SCIP_VAR* var, /**< given active problem variable */
5100 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5101 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
5102 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5103 * was not used (0) or was not used but is contained in the row (-1)
5104 */
5105 SCIP_Real bestslb, /**< closest simple lower bound of given variable */
5106 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
5107 SCIP_Real* closestvub, /**< pointer to store the LP sol value of the closest variable upper bound */
5108 int* closestvubidx /**< pointer to store the index of the closest vub; -1 if no vub was found */
5109 )
5110{
5111 int nvubs;
5112 int nbinvars;
5113
5114 assert(scip != NULL);
5115 assert(var != NULL);
5119 assert(rowcoefs != NULL);
5122 assert(closestvubidx != NULL);
5123
5126
5127 *closestvubidx = -1;
5129 if( nvubs > 0 )
5130 {
5131 SCIP_VAR** vubvars;
5132 SCIP_Real* vubcoefs;
5133 SCIP_Real* vubconsts;
5134 int i;
5135
5139
5140 for( i = 0; i < nvubs; i++ )
5141 {
5142 SCIP_Real rowcoefbinvar;
5143 SCIP_Real val1;
5144 SCIP_Real val2;
5145 SCIP_Real vubsol;
5146 SCIP_Real rowcoefsign;
5147 int probidxbinvar;
5148
5149 if( bestslb < vubconsts[i] )
5150 continue;
5151
5152 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
5153 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
5154 */
5155 if( REALABS(vubcoefs[i]) > MAXABSVBCOEF )
5156 continue;
5157
5158 /* use only variable upper bound u~_i * x_i + d_i with x_i binary and which are active */
5160
5161 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
5162 * ensures that the problem index is between 0 and nbinvars - 1
5163 */
5164 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
5165 continue;
5166
5168
5169 /* checks if current variable upper bound u~_i * x_i + d_i meets the following criteria
5170 * (let a_j = coefficient of y_j in current row,
5171 * l_j = closest simple lower bound imposed on y_j,
5172 * c_i = coefficient of x_i in current row)
5173 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k
5174 * if a > 0:
5175 * 1. l_j >= d_i
5176 * 2. a_j ( l_i - d_i ) + c_i >= 0
5177 * 3. a_j u~_i + c_i >= 0
5178 * if a < 0:
5179 * 1. l_j >= d_i
5180 * 2. a_j ( l_j - d_i ) + c_i <= 0
5181 * 3. a_j u~_i + c_i <= 0
5182 */
5183
5184 /* has already been used in the SNF relaxation */
5185 if( binvarused[probidxbinvar] == 1 )
5186 continue;
5187
5188 /* get the row coefficient */
5189 {
5190 SCIP_Real QUAD(tmp);
5193 }
5195
5197
5198 /* variable upper bound does not meet criteria */
5199 if( val2 < 0.0 || SCIPisInfinity(scip, val2) )
5200 continue;
5201
5203
5204 /* variable upper bound does not meet criteria */
5205 if( val1 < 0.0 )
5206 continue;
5207
5209 if( vubsol < *closestvub )
5210 {
5211 *closestvub = vubsol;
5212 *closestvubidx = i;
5213 }
5214 assert(*closestvubidx >= 0);
5215 }
5216 }
5217
5218 return SCIP_OKAY;
5219}
5220
5221/** determines the bounds to use for constructing the single-node-flow relaxation of a variable in
5222 * the given row.
5223 */
5224static
5226 SCIP* scip, /**< SCIP data structure */
5227 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5228 SCIP_VAR** vars, /**< array of problem variables */
5229 SCIP_Real* rowcoefs, /**< (dense) array of variable coefficients in the row */
5230 int* rowinds, /**< array with positions of non-zero values in the rowcoefs array */
5231 int varposinrow, /**< position of variable in the rowinds array for which the bounds should be determined */
5232 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5233 * was not used (0) or was not used but is contained in the row (-1)
5234 */
5235 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5236 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5237 SCIP_Real* bestlb, /**< pointer to store best lower bound for transformation */
5238 SCIP_Real* bestub, /**< pointer to store best upper bound for transformation */
5239 SCIP_Real* bestslb, /**< pointer to store best simple lower bound for transformation */
5240 SCIP_Real* bestsub, /**< pointer to store best simple upper bound for transformation */
5241 int* bestlbtype, /**< pointer to store type of best lower bound */
5242 int* bestubtype, /**< pointer to store type of best upper bound */
5243 int* bestslbtype, /**< pointer to store type of best simple lower bound */
5244 int* bestsubtype, /**< pointer to store type of best simple upper bound */
5245 SCIP_BOUNDTYPE* selectedbounds, /**< pointer to store the preferred bound for the transformation */
5246 SCIP_Bool* freevariable /**< pointer to store if variable is a free variable */
5247 )
5248{
5249 SCIP_VAR* var;
5250
5251 SCIP_Real rowcoef;
5252 SCIP_Real solval;
5253 SCIP_Real simplebound;
5254
5255 int probidx;
5256
5259 bestlbtype[varposinrow] = -3;
5260 bestubtype[varposinrow] = -3;
5261
5262 probidx = rowinds[varposinrow];
5263 var = vars[probidx];
5264 {
5265 SCIP_Real QUAD(tmp);
5268 }
5269
5271
5272 /* get closest simple lower bound and closest simple upper bound */
5275
5276 /* do not use too large bounds */
5277 if( bestslb[varposinrow] <= -MAXBOUND )
5279
5280 if( bestsub[varposinrow] >= MAXBOUND )
5282
5283 solval = SCIPgetSolVal(scip, sol, var);
5284
5285 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g(%d),%g(%d)]>:\n", varposinrow, rowcoef, SCIPvarGetName(var), probidx,
5287
5288 /* mixed integer set cannot be relaxed to 0-1 single node flow set because both simple bounds are -infinity
5289 * and infinity, respectively
5290 */
5292 {
5293 *freevariable = TRUE;
5294 return SCIP_OKAY;
5295 }
5296
5297 /* get closest lower bound that can be used to define the real variable y'_j in the 0-1 single node flow
5298 * relaxation
5299 */
5301 {
5304
5306 {
5307 SCIP_Real bestvlb;
5308 int bestvlbidx;
5309
5312 {
5315 }
5316 }
5317 }
5318
5319 /* get closest upper bound that can be used to define the real variable y'_j in the 0-1 single node flow
5320 * relaxation
5321 */
5323 {
5326
5328 {
5329 SCIP_Real bestvub;
5330 int bestvubidx;
5331
5334 {
5337 }
5338 }
5339 }
5341
5342 /* mixed integer set cannot be relaxed to 0-1 single node flow set because there are no suitable bounds
5343 * to define the transformed variable y'_j
5344 */
5346 {
5347 *freevariable = TRUE;
5348 return SCIP_OKAY;
5349 }
5350
5352
5353 /* select best upper bound if it is closer to the LP value of y_j and best lower bound otherwise and use this bound
5354 * to define the real variable y'_j with 0 <= y'_j <= u'_j x_j in the 0-1 single node flow relaxation;
5355 * prefer variable bounds
5356 */
5358 {
5360 }
5361 else if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow])
5362 && bestubtype[varposinrow] >= 0 )
5363 {
5365 }
5366 else if( SCIPisLE(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) )
5367 {
5369 }
5370 else
5371 {
5374 }
5375
5377 {
5378 int vlbvarprobidx;
5380
5381 /* mark binary variable of vlb so that it is not used for other continuous variables
5382 * by setting it's position in the aggrrow to a negative value
5383 */
5386 }
5388 {
5389 int vubvarprobidx;
5391
5392 /* mark binary variable of vub so that it is not used for other continuous variables
5393 * by setting it's position in the aggrrow to a negative value
5394 */
5397 }
5398
5399 return SCIP_OKAY; /*lint !e438*/
5400}
5401
5402/** construct a 0-1 single node flow relaxation (with some additional simple constraints) of a mixed integer set
5403 * corresponding to the given aggrrow a * x <= rhs
5404 */
5405static
5407 SCIP* scip, /**< SCIP data structure */
5408 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
5409 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5410 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5411 SCIP_Real* rowcoefs, /**< array of coefficients of row */
5412 QUAD(SCIP_Real rowrhs), /**< pointer to right hand side of row */
5413 int* rowinds, /**< array of variables problem indices for non-zero coefficients in row */
5414 int nnz, /**< number of non-zeros in row */
5415 SNF_RELAXATION* snf, /**< stores the sign of the transformed variable in summation */
5416 SCIP_Bool* success, /**< stores whether the transformation was valid */
5417 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
5418 )
5419{
5420 SCIP_VAR** vars;
5421 int i;
5422 int nnonbinvarsrow;
5424 int nbinvars;
5425 SCIP_Real QUAD(transrhs);
5426
5427 /* arrays to store the selected bound for each non-binary variable in the row */
5428 SCIP_Real* bestlb;
5429 SCIP_Real* bestub;
5430 SCIP_Real* bestslb;
5431 SCIP_Real* bestsub;
5432 int* bestlbtype;
5433 int* bestubtype;
5434 int* bestslbtype;
5435 int* bestsubtype;
5437
5438 *success = FALSE;
5439
5440 SCIPdebugMsg(scip, "--------------------- construction of SNF relaxation ------------------------------------\n");
5441
5444
5454
5455 /* sort descending to have continuous variables first */
5456 SCIPsortDownInt(rowinds, nnz);
5457
5458 /* array to store whether a binary variable is in the row (-1) or has been used (1) due to variable bound usage */
5460
5461 for( i = nnz - 1; i >= 0 && rowinds[i] < nbinvars; --i )
5462 binvarused[rowinds[i]] = -1;
5463
5464 nnonbinvarsrow = i + 1;
5465 /* determine the bounds to use for transforming the non-binary variables */
5466 for( i = 0; i < nnonbinvarsrow; ++i )
5467 {
5468 SCIP_Bool freevariable;
5469
5470 assert(rowinds[i] >= nbinvars);
5471
5474
5475 if( freevariable )
5476 {
5477 int j;
5478
5479 /* clear binvarused at indices of binary variables of row */
5480 for( j = nnz - 1; j >= nnonbinvarsrow; --j )
5481 binvarused[rowinds[j]] = 0;
5482
5483 /* clear binvarused at indices of selected variable bounds */
5484 for( j = 0; j < i; ++j )
5485 {
5487 {
5488 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(vars[rowinds[j]]);
5490 }
5491 else if( selectedbounds[j] == SCIP_BOUNDTYPE_UPPER && bestubtype[j] >= 0 )
5492 {
5493 SCIP_VAR** vubvars = SCIPvarGetVubVars(vars[rowinds[j]]);
5495 }
5496 }
5497
5498 /* terminate */
5499 goto TERMINATE;
5500 }
5501 }
5502
5504 QUAD_ASSIGN_Q(transrhs, rowrhs);
5505 snf->ntransvars = 0;
5506
5507 assert(snf->transvarcoefs != NULL); /* for lint */
5508 assert(snf->transvarvubcoefs != NULL);
5509 assert(snf->transbinvarsolvals != NULL);
5510 assert(snf->transcontvarsolvals != NULL);
5511 assert(snf->aggrconstants != NULL);
5512 assert(snf->aggrcoefscont != NULL);
5513 assert(snf->origcontvars != NULL);
5514 assert(snf->origbinvars != NULL);
5515 assert(snf->aggrcoefsbin != NULL);
5516
5517 /* transform non-binary variables */
5518 for( i = 0; i < nnonbinvarsrow; ++i )
5519 {
5520 SCIP_VAR* var;
5521 SCIP_Real QUAD(rowcoef);
5522 SCIP_Real solval;
5523 int probidx;
5524
5525 probidx = rowinds[i];
5526 var = vars[probidx];
5528 solval = SCIPgetSolVal(scip, sol, var);
5529
5531
5533 {
5534 /* use bestlb to define y'_j */
5535
5538 assert(bestsubtype[i] == -1 || bestsubtype[i] == -2);
5540
5541 /* store for y_j that bestlb is the bound used to define y'_j and that y'_j is the associated real variable
5542 * in the relaxed set
5543 */
5544 snf->origcontvars[snf->ntransvars] = probidx;
5545
5546 if( bestlbtype[i] < 0 )
5547 {
5548 SCIP_Real QUAD(val);
5549 SCIP_Real QUAD(contsolval);
5550 SCIP_Real QUAD(rowcoeftimesbestsub);
5551
5552 /* use simple lower bound in bestlb = l_j <= y_j <= u_j = bestsub to define
5553 * 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
5554 * 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,
5555 * put j into the set
5556 * N2 if a_j > 0
5557 * N1 if a_j < 0
5558 * and update the right hand side of the constraint in the relaxation
5559 * rhs = rhs - a_j u_j
5560 */
5562 SCIPquadprecProdQQ(val, val, rowcoef);
5565
5566 if( bestlbtype[i] == -2 || bestsubtype[i] == -2 )
5567 *localbdsused = TRUE;
5568
5570
5571 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5572 snf->origbinvars[snf->ntransvars] = -1;
5573 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5574
5576 {
5577 snf->transvarcoefs[snf->ntransvars] = - 1;
5578 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5579 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5580 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5581
5582 /* aggregation information for y'_j */
5583 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestsub);
5584 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5585 }
5586 else
5587 {
5589 snf->transvarcoefs[snf->ntransvars] = 1;
5590 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5591 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5592 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5593
5594 /* aggregation information for y'_j */
5595 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestsub);
5596 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5597 }
5598 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestsub);
5599
5600 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
5601 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5602 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestsub), QUAD_TO_DBL(rowcoef), bestsub[i], QUAD_TO_DBL(transrhs));
5603 }
5604 else
5605 {
5606 SCIP_Real QUAD(rowcoefbinary);
5607 SCIP_Real varsolvalbinary;
5608 SCIP_Real QUAD(val);
5609 SCIP_Real QUAD(contsolval);
5610 SCIP_Real QUAD(rowcoeftimesvlbconst);
5611 int vlbvarprobidx;
5612
5614 SCIP_Real* vlbconsts = SCIPvarGetVlbConstants(var);
5615 SCIP_Real* vlbcoefs = SCIPvarGetVlbCoefs(var);
5616
5617 /* use variable lower bound in bestlb = l~_j x_j + d_j <= y_j <= u_j = bestsub to define
5618 * 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
5619 * 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,
5620 * where c_j is the coefficient of x_j in the row, put j into the set
5621 * N2 if a_j > 0
5622 * N1 if a_j < 0
5623 * and update the right hand side of the constraint in the relaxation
5624 * rhs = rhs - a_j d_j
5625 */
5626
5630
5633
5636 {
5637 SCIP_Real QUAD(tmp);
5638
5643 }
5644
5646
5647 /* clear the binvarpos array, since the variable has been processed */
5649
5650 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5651 snf->origbinvars[snf->ntransvars] = vlbvarprobidx;
5652
5654 {
5655 snf->transvarcoefs[snf->ntransvars] = - 1;
5656 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5657 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5658 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5659
5660 /* aggregation information for y'_j */
5661 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5662 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5663 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvlbconst);
5664 }
5665 else
5666 {
5668 snf->transvarcoefs[snf->ntransvars] = 1;
5669 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5670 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5671 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5672
5673 /* aggregation information for y'_j */
5674 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
5675 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5676 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvlbconst);
5677 }
5678 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvlbconst);
5679
5680 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5681 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5683 vlbconsts[bestlbtype[i]], snf->transrhs );
5684 }
5685 }
5686 else
5687 {
5688 /* use bestub to define y'_j */
5689
5692 assert(bestslbtype[i] == -1 || bestslbtype[i] == -2);
5694
5695 /* store for y_j that y'_j is the associated real variable
5696 * in the relaxed set
5697 */
5698 snf->origcontvars[snf->ntransvars] = probidx;
5699
5700 if( bestubtype[i] < 0 )
5701 {
5702 SCIP_Real QUAD(val);
5703 SCIP_Real QUAD(contsolval);
5704 SCIP_Real QUAD(rowcoeftimesbestslb);
5705
5706 /* use simple upper bound in bestslb = l_j <= y_j <= u_j = bestub to define
5707 * 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
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 * put j into the set
5710 * N1 if a_j > 0
5711 * N2 if a_j < 0
5712 * and update the right hand side of the constraint in the relaxation
5713 * rhs = rhs - a_j l_j
5714 */
5715 SCIPquadprecSumDD(val, bestub[i], - bestslb[i]);
5716 SCIPquadprecProdQQ(val, val, rowcoef);
5719
5720 if( bestubtype[i] == -2 || bestslbtype[i] == -2 )
5721 *localbdsused = TRUE;
5722
5724
5725 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5726 snf->origbinvars[snf->ntransvars] = -1;
5727 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5728
5730 {
5731 snf->transvarcoefs[snf->ntransvars] = 1;
5732 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5733 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5734 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5735
5736 /* aggregation information for y'_j */
5737 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5738 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestslb);
5739 }
5740 else
5741 {
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
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
5784
5787
5788 /* clear the binvarpos array, since the variable has been processed */
5790
5793 {
5794 SCIP_Real QUAD(tmp);
5799 }
5800
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
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 {
5820 snf->transvarcoefs[snf->ntransvars] = - 1;
5821 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5822 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5823 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5824
5825 /* aggregation information for y'_j */
5826 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5827 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5828 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvubconst);
5829 }
5830 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvubconst);
5831
5832 /* store for x_j that y'_j is the associated real variable in the 0-1 single node flow relaxation */
5833
5834 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5835 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5837 vubconsts[bestubtype[i]], QUAD_TO_DBL(transrhs));
5838 }
5839 }
5840
5841 /* make sure the coefficient is not negative due to small numerical rounding errors */
5842 assert(snf->transvarvubcoefs[snf->ntransvars] > -QUAD_EPSILON);
5843 snf->transvarvubcoefs[snf->ntransvars] = MAX(snf->transvarvubcoefs[snf->ntransvars], 0.0);
5844
5845 ++snf->ntransvars;
5846 }
5847
5848 snf->transrhs = QUAD_TO_DBL(transrhs);
5849
5850 /* transform remaining binary variables of row */
5851 for( i = nnonbinvarsrow; i < nnz; ++i )
5852 {
5853 SCIP_VAR* var;
5854 SCIP_Real QUAD(rowcoef);
5855 int probidx;
5856 SCIP_Real val;
5857 SCIP_Real contsolval;
5858 SCIP_Real varsolval;
5859
5860 probidx = rowinds[i];
5861 /* variable should be binary */
5863
5864 /* binary variable was processed together with a non-binary variable */
5865 if( binvarused[probidx] == 0 )
5866 continue;
5867
5868 /* binary variable was not processed yet, so the binvarused value sould be -1 */
5869 assert(binvarused[probidx] == -1);
5870
5871 /* set binvarused to zero since it has been processed */
5872 binvarused[probidx] = 0;
5873
5874 var = vars[probidx];
5876
5878
5880 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g, %g]>:\n", i, QUAD_TO_DBL(rowcoef), SCIPvarGetName(var), probidx, varsolval,
5882
5883 /* define
5884 * y'_j = c_j x_j with 0 <= y'_j <= c_j x_j if c_j > 0
5885 * y'_j = - c_j x_j with 0 <= y'_j <= - c_j x_j if c_j < 0,
5886 * where c_j is the coefficient of x_j in the row and put j into the set
5887 * N1 if c_j > 0
5888 * N2 if c_j < 0.
5889 */
5890 val = QUAD_TO_DBL(rowcoef);
5892
5893 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5894 snf->origbinvars[snf->ntransvars] = probidx;
5895 snf->origcontvars[snf->ntransvars] = -1;
5896 snf->aggrcoefscont[snf->ntransvars] = 0.0;
5897 snf->aggrconstants[snf->ntransvars] = 0.0;
5898
5900 {
5901 snf->transvarcoefs[snf->ntransvars] = 1;
5902 snf->transvarvubcoefs[snf->ntransvars] = val;
5903 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
5904 snf->transcontvarsolvals[snf->ntransvars] = contsolval;
5905
5906 /* aggregation information for y'_j */
5907 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5908 }
5909 else
5910 {
5912 snf->transvarcoefs[snf->ntransvars] = - 1;
5913 snf->transvarvubcoefs[snf->ntransvars] = - val;
5914 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
5915 snf->transcontvarsolvals[snf->ntransvars] = - contsolval;
5916
5917 /* aggregation information for y'_j */
5918 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5919 }
5920
5921 assert(snf->transvarcoefs[snf->ntransvars] == 1 || snf->transvarcoefs[snf->ntransvars] == - 1 );
5922 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[snf->ntransvars], 0.0)
5923 && SCIPisFeasLE(scip, snf->transbinvarsolvals[snf->ntransvars], 1.0));
5924 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[snf->ntransvars], 0.0)
5925 && !SCIPisInfinity(scip, snf->transvarvubcoefs[snf->ntransvars]));
5926
5927 SCIPdebugMsg(scip, " --> ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s))\n", snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars,
5928 snf->transvarvubcoefs[snf->ntransvars], snf->ntransvars, SCIPvarGetName(var) );
5929
5930 /* updates number of variables in transformed problem */
5931 snf->ntransvars++;
5932 }
5933
5934 /* construction was successful */
5935 *success = TRUE;
5936
5937#ifdef SCIP_DEBUG
5938 SCIPdebugMsg(scip, "constraint in constructed 0-1 single node flow relaxation: ");
5939 for( i = 0; i < snf->ntransvars; i++ )
5940 {
5941 SCIPdebugMsgPrint(scip, "%s y'_%d ", snf->transvarcoefs[i] == 1 ? "+" : "-", i);
5942 }
5943 SCIPdebugMsgPrint(scip, "<= %g\n", snf->transrhs);
5944#endif
5945
5946 TERMINATE:
5947
5958
5959 return SCIP_OKAY;
5960}
5961
5962/** allocate buffer arrays for storing the single-node-flow relaxation */
5963static
5965 SCIP* scip, /**< SCIP data structure */
5966 SNF_RELAXATION* snf, /**< pointer to snf relaxation to be destroyed */
5967 int nvars /**< number of active problem variables */
5968 )
5969{
5970 SCIP_CALL( SCIPallocBufferArray(scip, &snf->transvarcoefs, nvars) );
5971 SCIP_CALL( SCIPallocBufferArray(scip, &snf->transbinvarsolvals, nvars) );
5972 SCIP_CALL( SCIPallocBufferArray(scip, &snf->transcontvarsolvals, nvars) );
5973 SCIP_CALL( SCIPallocBufferArray(scip, &snf->transvarvubcoefs, nvars) );
5974 SCIP_CALL( SCIPallocBufferArray(scip, &snf->origbinvars, nvars) );
5975 SCIP_CALL( SCIPallocBufferArray(scip, &snf->origcontvars, nvars) );
5976 SCIP_CALL( SCIPallocBufferArray(scip, &snf->aggrcoefsbin, nvars) );
5977 SCIP_CALL( SCIPallocBufferArray(scip, &snf->aggrcoefscont, nvars) );
5978 SCIP_CALL( SCIPallocBufferArray(scip, &snf->aggrconstants, nvars) );
5979
5980 return SCIP_OKAY;
5981}
5982
5983/** free buffer arrays for storing the single-node-flow relaxation */
5984static
5986 SCIP* scip, /**< SCIP data structure */
5987 SNF_RELAXATION* snf /**< pointer to snf relaxation to be destroyed */
5988 )
5989{
5990 SCIPfreeBufferArray(scip, &snf->aggrconstants);
5991 SCIPfreeBufferArray(scip, &snf->aggrcoefscont);
5992 SCIPfreeBufferArray(scip, &snf->aggrcoefsbin);
5993 SCIPfreeBufferArray(scip, &snf->origcontvars);
5994 SCIPfreeBufferArray(scip, &snf->origbinvars);
5995 SCIPfreeBufferArray(scip, &snf->transvarvubcoefs);
5996 SCIPfreeBufferArray(scip, &snf->transcontvarsolvals);
5997 SCIPfreeBufferArray(scip, &snf->transbinvarsolvals);
5998 SCIPfreeBufferArray(scip, &snf->transvarcoefs);
5999}
6000
6001/** solve knapsack problem in maximization form with "<" constraint approximately by greedy; if needed, one can provide
6002 * arrays to store all selected items and all not selected items
6003 */
6004static
6006 SCIP* scip, /**< SCIP data structure */
6007 int nitems, /**< number of available items */
6008 SCIP_Real* weights, /**< item weights */
6009 SCIP_Real* profits, /**< item profits */
6010 SCIP_Real capacity, /**< capacity of knapsack */
6011 int* items, /**< item numbers */
6012 int* solitems, /**< array to store items in solution, or NULL */
6013 int* nonsolitems, /**< array to store items not in solution, or NULL */
6014 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
6015 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
6016 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
6017 )
6018{
6019 SCIP_Real* tempsort;
6020 SCIP_Real solitemsweight;
6021 SCIP_Real mediancapacity;
6022 int j;
6023 int i;
6024 int criticalitem;
6025
6026 assert(weights != NULL);
6027 assert(profits != NULL);
6028 assert(SCIPisFeasGE(scip, capacity, 0.0));
6029 assert(!SCIPisInfinity(scip, capacity));
6030 assert(items != NULL);
6031 assert(nitems >= 0);
6032
6033 if( solitems != NULL )
6034 {
6035 *nsolitems = 0;
6036 *nnonsolitems = 0;
6037 }
6038 if( solval != NULL )
6039 *solval = 0.0;
6040
6041 /* allocate memory for temporary array used for sorting; array should contain profits divided by corresponding weights (p_1 / w_1 ... p_n / w_n )*/
6043
6044 /* initialize temporary array */
6045 for( i = nitems - 1; i >= 0; --i )
6046 tempsort[i] = profits[i] / weights[i];
6047
6048 /* decrease capacity slightly to make it tighter than the original capacity */
6049 mediancapacity = capacity * (1 - SCIPfeastol(scip));
6050
6051 /* rearrange items around */
6053
6054 /* free temporary array */
6056
6057 /* select items as long as they fit into the knapsack */
6058 solitemsweight = 0.0;
6059 for( j = 0; j < nitems && SCIPisFeasLT(scip, solitemsweight + weights[j], capacity); j++ )
6060 {
6061 if( solitems != NULL )
6062 {
6064 (*nsolitems)++;
6065 }
6066 if( solval != NULL )
6067 (*solval) += profits[j];
6068 solitemsweight += weights[j];
6069 }
6070
6071 /* continue to put items into the knapsack if they entirely fit */
6072 for( ; j < nitems; j++ )
6073 {
6074 if( SCIPisFeasLT(scip, solitemsweight + weights[j], capacity) )
6075 {
6076 if( solitems != NULL )
6077 {
6079 (*nsolitems)++;
6080 }
6081 if( solval != NULL )
6082 (*solval) += profits[j];
6083 solitemsweight += weights[j];
6084 }
6085 else if( solitems != NULL )
6086 {
6088 (*nnonsolitems)++;
6089 }
6090 }
6091
6092 return SCIP_OKAY;
6093}
6094
6095
6096/** build the flow cover which corresponds to the given exact or approximate solution of KP^SNF; given unfinished
6097 * flow cover contains variables which have been fixed in advance
6098 */
6099static
6101 SCIP* scip, /**< SCIP data structure */
6102 int* coefs, /**< coefficient of all real variables in N1&N2 */
6103 SCIP_Real* vubcoefs, /**< coefficient in vub of all real variables in N1&N2 */
6104 SCIP_Real rhs, /**< right hand side of 0-1 single node flow constraint */
6105 int* solitems, /**< items in knapsack */
6106 int* nonsolitems, /**< items not in knapsack */
6107 int nsolitems, /**< number of items in knapsack */
6108 int nnonsolitems, /**< number of items not in knapsack */
6109 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6110 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6111 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6112 QUAD(SCIP_Real* flowcoverweight), /**< pointer to store weight of flow cover */
6113 SCIP_Real* lambda /**< pointer to store lambda */
6114 )
6115{
6116 int j;
6117 SCIP_Real QUAD(tmp);
6118
6119 assert(scip != NULL);
6120 assert(coefs != NULL);
6121 assert(vubcoefs != NULL);
6122 assert(solitems != NULL);
6124 assert(nsolitems >= 0);
6125 assert(nnonsolitems >= 0);
6130 assert(lambda != NULL);
6131
6132 /* get flowcover status for each item */
6133 for( j = 0; j < nsolitems; j++ )
6134 {
6135 /* j in N1 with z°_j = 1 => j in N1\C1 */
6136 if( coefs[solitems[j]] == 1 )
6137 {
6138 flowcoverstatus[solitems[j]] = -1;
6139 (*nnonflowcovervars)++;
6140 }
6141 /* j in N2 with z_j = 1 => j in C2 */
6142 else
6143 {
6144 assert(coefs[solitems[j]] == -1);
6146 (*nflowcovervars)++;
6148 }
6149 }
6150 for( j = 0; j < nnonsolitems; j++ )
6151 {
6152 /* j in N1 with z°_j = 0 => j in C1 */
6153 if( coefs[nonsolitems[j]] == 1 )
6154 {
6156 (*nflowcovervars)++;
6158 }
6159 /* j in N2 with z_j = 0 => j in N2\C2 */
6160 else
6161 {
6162 assert(coefs[nonsolitems[j]] == -1);
6164 (*nnonflowcovervars)++;
6165 }
6166 }
6167
6168 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6170 *lambda = QUAD_TO_DBL(tmp);
6171}
6172
6173#ifndef NO_EXACT_KNAPSACK
6174
6175/** checks, whether the given scalar scales the given value to an integral number with error in the given bounds */
6176static
6177SCIP_Bool isIntegralScalar(
6178 SCIP_Real val, /**< value that should be scaled to an integral value */
6179 SCIP_Real scalar, /**< scalar that should be tried */
6180 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
6181 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
6182 )
6183{
6184 SCIP_Real sval;
6185 SCIP_Real downval;
6186 SCIP_Real upval;
6187
6188 assert(mindelta <= 0.0);
6189 assert(maxdelta >= 0.0);
6190
6191 sval = val * scalar;
6192 downval = floor(sval);
6193 upval = ceil(sval);
6194
6196}
6197
6198/** get integral number with error in the bounds which corresponds to given value scaled by a given scalar;
6199 * should be used in connection with isIntegralScalar()
6200 */
6201static
6202SCIP_Longint getIntegralVal(
6203 SCIP_Real val, /**< value that should be scaled to an integral value */
6204 SCIP_Real scalar, /**< scalar that should be tried */
6205 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
6206 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
6207 )
6208{
6209 SCIP_Real sval;
6210 SCIP_Real upval;
6211 SCIP_Longint intval;
6212
6213 assert(mindelta <= 0.0);
6214 assert(maxdelta >= 0.0);
6215
6216 sval = val * scalar;
6217 upval = ceil(sval);
6218
6219 if( SCIPrelDiff(sval, upval) >= mindelta )
6220 intval = (SCIP_Longint) upval;
6221 else
6222 intval = (SCIP_Longint) (floor(sval));
6223
6224 return intval;
6225}
6226
6227/** get a flow cover (C1, C2) for a given 0-1 single node flow set
6228 * {(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},
6229 * 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
6230 */
6231static
6233 SCIP* scip, /**< SCIP data structure */
6234 SNF_RELAXATION* snf, /**< the single node flow relaxation */
6235 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6236 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6237 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6238 SCIP_Real* lambda, /**< pointer to store lambda */
6239 SCIP_Bool* found /**< pointer to store whether a cover was found */
6240 )
6241{
6242 SCIP_Real* transprofitsint;
6243 SCIP_Real* transprofitsreal;
6244 SCIP_Real* transweightsreal;
6245 SCIP_Longint* transweightsint;
6246 int* items;
6247 int* itemsint;
6248 int* nonsolitems;
6249 int* solitems;
6250 SCIP_Real QUAD(flowcoverweight);
6251 SCIP_Real QUAD(flowcoverweightafterfix);
6252 SCIP_Real n1itemsweight;
6253 SCIP_Real n2itemsminweight;
6254 SCIP_Real scalar;
6255 SCIP_Real transcapacityreal;
6256#if !defined(NDEBUG) || defined(SCIP_DEBUG)
6257 SCIP_Bool kpexact;
6258#endif
6259 SCIP_Bool scalesuccess;
6260 SCIP_Bool transweightsrealintegral;
6261 SCIP_Longint transcapacityint;
6263 int nitems;
6264 int nn1items;
6266 int nnonsolitems;
6267 int nsolitems;
6268 int j;
6269
6270 assert(scip != NULL);
6271 assert(snf->transvarcoefs != NULL);
6272 assert(snf->transbinvarsolvals != NULL);
6273 assert(snf->transvarvubcoefs != NULL);
6274 assert(snf->ntransvars > 0);
6278 assert(lambda != NULL);
6279 assert(found != NULL);
6280
6281 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
6282
6283 /* get data structures */
6284 SCIP_CALL( SCIPallocBufferArray(scip, &items, snf->ntransvars) );
6285 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
6290 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
6292
6294 *found = FALSE;
6295 *nflowcovervars = 0;
6296 *nnonflowcovervars = 0;
6297
6302#if !defined(NDEBUG) || defined(SCIP_DEBUG)
6303 kpexact = FALSE;
6304#endif
6305
6306 /* fix some variables in advance according to the following fixing strategy
6307 * put j into N1\C1, if j in N1 and x*_j = 0,
6308 * put j into C1, if j in N1 and x*_j = 1,
6309 * put j into C2, if j in N2 and x*_j = 1,
6310 * put j into N2\C2, if j in N2 and x*_j = 0
6311 * and get the set of the remaining variables
6312 */
6313 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
6314 nitems = 0;
6315 nn1items = 0;
6316 n1itemsweight = 0.0;
6318 for( j = 0; j < snf->ntransvars; j++ )
6319 {
6320 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
6321 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
6322 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
6323
6324 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
6325 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
6326 {
6327 flowcoverstatus[j] = -1;
6328 (*nnonflowcovervars)++;
6329 continue;
6330 }
6331
6332 /* x*_j is fractional */
6333 if( !SCIPisFeasIntegral(scip, snf->transbinvarsolvals[j]) )
6334 {
6335 items[nitems] = j;
6336 nitems++;
6337 if( snf->transvarcoefs[j] == 1 )
6338 {
6339 n1itemsweight += snf->transvarvubcoefs[j];
6340 nn1items++;
6341 }
6342 else
6343 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
6344 }
6345 /* j is in N1 and x*_j = 0 */
6346 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
6347 {
6348 flowcoverstatus[j] = -1;
6349 (*nnonflowcovervars)++;
6350 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
6351 }
6352 /* j is in N1 and x*_j = 1 */
6353 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
6354 {
6355 flowcoverstatus[j] = 1;
6356 (*nflowcovervars)++;
6358 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
6359 }
6360 /* j is in N2 and x*_j = 1 */
6361 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
6362 {
6363 flowcoverstatus[j] = 1;
6364 (*nflowcovervars)++;
6365 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
6366 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
6367 }
6368 /* j is in N2 and x*_j = 0 */
6369 else
6370 {
6371 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
6372 flowcoverstatus[j] = -1;
6373 (*nnonflowcovervars)++;
6374 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
6375 }
6376 }
6377 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
6378 assert(nn1items >= 0);
6379
6380 /* to find a flow cover, transform the following knapsack problem
6381 *
6382 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
6383 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
6384 * z_j in {0,1} for all j in N1 & N2
6385 *
6386 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6387 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
6388 *
6389 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6390 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
6391 * z°_j in {0,1} for all j in N1
6392 * z_j in {0,1} for all j in N2,
6393 * and solve it approximately under consideration of the fixing,
6394 * or
6395 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6396 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
6397 * and multiplying the constraint by a suitable scalar C
6398 *
6399 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6400 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
6401 * z°_j in {0,1} for all j in N1
6402 * z_j in {0,1} for all j in N2,
6403 * where
6404 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
6405 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
6406 * and solve it exactly under consideration of the fixing.
6407 */
6408 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
6409
6410 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
6412 for( j = 0; j < nitems; j++ )
6413 {
6414 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
6415
6418
6419 if( snf->transvarcoefs[items[j]] == 1 )
6420 {
6421 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
6422 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6423 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6424 }
6425 else
6426 {
6427 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
6428 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6429 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6430 }
6431 }
6432 /* get capacity of knapsack constraint in KP^SNF_rat */
6434 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
6436
6437 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
6438 * is less than or equal to zero
6439 */
6440 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
6441 {
6442 assert(!(*found));
6443 goto TERMINATE;
6444 }
6445
6446 /* KP^SNF_rat has been solved by fixing some variables in advance */
6447 assert(nitems >= 0);
6448 if( nitems == 0)
6449 {
6450 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6452 *lambda = QUAD_TO_DBL(flowcoverweight);
6453 *found = TRUE;
6454 goto TERMINATE;
6455 }
6456
6457 /* Use the following strategy
6458 * solve KP^SNF_int exactly, if a suitable factor C is found and (nitems*capacity) <= MAXDYNPROGSPACE,
6459 * solve KP^SNF_rat approximately, otherwise
6460 */
6461
6462 /* find a scaling factor C */
6464 {
6465 /* weights are already integral */
6466 scalar = 1.0;
6468 }
6469 else
6470 {
6473 &scalesuccess) );
6474 }
6475
6476 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
6477 nsolitems = -1;
6478 nnonsolitems = -1;
6479
6480 /* suitable factor C was found*/
6481 if( scalesuccess )
6482 {
6483 SCIP_Real tmp1;
6484 SCIP_Real tmp2;
6485
6486 /* transform KP^SNF to KP^SNF_int */
6487 for( j = 0; j < nitems; ++j )
6488 {
6491 itemsint[j] = items[j];
6492 }
6494 {
6496 transcapacityint -= 1;
6497 }
6498 else
6503
6504 tmp1 = (SCIP_Real) (nitems + 1);
6505 tmp2 = (SCIP_Real) ((transcapacityint) + 1);
6506 if( transcapacityint * nitems <= MAXDYNPROGSPACE && tmp1 * tmp2 <= INT_MAX / 8.0)
6507 {
6508 SCIP_Bool success;
6509
6510 /* solve KP^SNF_int by dynamic programming */
6513
6514 if( !success )
6515 {
6516 /* solve KP^SNF_rat approximately */
6519 }
6520#if !defined(NDEBUG) || defined(SCIP_DEBUG)
6521 else
6522 kpexact = TRUE;
6523#endif
6524 }
6525 else
6526 {
6527 /* solve KP^SNF_rat approximately */
6530 assert(!kpexact);
6531 }
6532 }
6533 else
6534 {
6535 /* solve KP^SNF_rat approximately */
6538 assert(!kpexact);
6539 }
6540
6541 assert(nsolitems != -1);
6542 assert(nnonsolitems != -1);
6543
6544 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
6546 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6548 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6549
6550 /* if the found structure is not a flow cover, because of scaling, solve KP^SNF_rat approximately */
6551 if( SCIPisFeasLE(scip, *lambda, 0.0) )
6552 {
6553 assert(kpexact);
6554
6555 /* solve KP^SNF_rat approximately */
6558#ifdef SCIP_DEBUG /* this time only for SCIP_DEBUG, because only then, the variable is used again */
6559 kpexact = FALSE;
6560#endif
6561
6562 /* build the flow cover from the solution of KP^SNF_rat and the fixing */
6566
6568 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6570 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6571 }
6572 *found = SCIPisFeasGT(scip, *lambda, 0.0);
6573
6574 TERMINATE:
6575 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
6576#ifdef SCIP_DEBUG
6577 if( *found )
6578 {
6579 SCIPdebugMsg(scip, "2. %s solution:\n", kpexact ? "exact" : "approximate");
6580 for( j = 0; j < snf->ntransvars; j++ )
6581 {
6582 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
6583 {
6584 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6585 }
6586 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
6587 {
6588 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6589 }
6590 }
6591 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
6592 }
6593#endif
6594
6595 /* free data structures */
6604
6605 return SCIP_OKAY;
6606}
6607
6608#else
6609
6610/** get a flow cover \f$(C1, C2)\f$ for a given 0-1 single node flow set
6611 * \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$,
6612 * i.e., get sets \f$ C1 \subset N1 \f$ and \f$ C2 \subset N2 \f$ with
6613 * \f$ \sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda \f$ and \f$ lambda > 0 \f$
6614 */
6615static
6617 SCIP* scip, /**< SCIP data structure */
6618 SNF_RELAXATION* snf, /**< the 0-1 single node flow relaxation */
6619 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6620 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6621 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6622 SCIP_Real* lambda, /**< pointer to store lambda */
6623 SCIP_Bool* found /**< pointer to store whether a cover was found */
6624 )
6625{
6626 SCIP_Real* transprofitsreal;
6627 SCIP_Real* transweightsreal;
6628 SCIP_Longint* transweightsint;
6629 int* items;
6630 int* itemsint;
6631 int* nonsolitems;
6632 int* solitems;
6633 SCIP_Real QUAD(flowcoverweight);
6634 SCIP_Real n1itemsweight;
6635 SCIP_Real n2itemsminweight;
6636 SCIP_Real transcapacityreal;
6637 int nitems;
6638#ifndef NDEBUG
6639 int nn1items = 0;
6640#endif
6641 int nnonsolitems;
6642 int nsolitems;
6643 int j;
6644
6645 assert(scip != NULL);
6646 assert(snf->transvarcoefs != NULL);
6647 assert(snf->transbinvarsolvals != NULL);
6648 assert(snf->transvarvubcoefs != NULL);
6649 assert(snf->ntransvars > 0);
6653 assert(lambda != NULL);
6654 assert(found != NULL);
6655
6656 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
6657
6658 /* get data structures */
6659 SCIP_CALL( SCIPallocBufferArray(scip, &items, snf->ntransvars) );
6660 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
6664 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
6666
6668 *found = FALSE;
6669 *nflowcovervars = 0;
6670 *nnonflowcovervars = 0;
6671
6673
6674 /* fix some variables in advance according to the following fixing strategy
6675 * put j into N1\C1, if j in N1 and x*_j = 0,
6676 * put j into C1, if j in N1 and x*_j = 1,
6677 * put j into C2, if j in N2 and x*_j = 1,
6678 * put j into N2\C2, if j in N2 and x*_j = 0
6679 * and get the set of the remaining variables
6680 */
6681 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
6682 nitems = 0;
6683 n1itemsweight = 0.0;
6685 for( j = 0; j < snf->ntransvars; j++ )
6686 {
6687 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
6688 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
6689 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
6690
6691 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
6692 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
6693 {
6694 flowcoverstatus[j] = -1;
6695 (*nnonflowcovervars)++;
6696 continue;
6697 }
6698
6699 /* x*_j is fractional */
6700 if( !SCIPisFeasIntegral(scip, snf->transbinvarsolvals[j]) )
6701 {
6702 items[nitems] = j;
6703 nitems++;
6704 if( snf->transvarcoefs[j] == 1 )
6705 {
6706 n1itemsweight += snf->transvarvubcoefs[j];
6707#ifndef NDEBUG
6708 nn1items++;
6709#endif
6710 }
6711 else
6712 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
6713 }
6714 /* j is in N1 and x*_j = 0 */
6715 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
6716 {
6717 flowcoverstatus[j] = -1;
6718 (*nnonflowcovervars)++;
6719 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
6720 }
6721 /* j is in N1 and x*_j = 1 */
6722 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
6723 {
6724 flowcoverstatus[j] = 1;
6725 (*nflowcovervars)++;
6727 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
6728 }
6729 /* j is in N2 and x*_j = 1 */
6730 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
6731 {
6732 flowcoverstatus[j] = 1;
6733 (*nflowcovervars)++;
6734 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
6735 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
6736 }
6737 /* j is in N2 and x*_j = 0 */
6738 else
6739 {
6740 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
6741 flowcoverstatus[j] = -1;
6742 (*nnonflowcovervars)++;
6743 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
6744 }
6745 }
6746 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
6747 assert(nn1items >= 0);
6748
6749 /* to find a flow cover, transform the following knapsack problem
6750 *
6751 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
6752 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
6753 * z_j in {0,1} for all j in N1 & N2
6754 *
6755 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6756 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
6757 *
6758 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6759 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
6760 * z°_j in {0,1} for all j in N1
6761 * z_j in {0,1} for all j in N2,
6762 * and solve it approximately under consideration of the fixing,
6763 * or
6764 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6765 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
6766 * and multiplying the constraint by a suitable scalar C
6767 *
6768 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6769 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
6770 * z°_j in {0,1} for all j in N1
6771 * z_j in {0,1} for all j in N2,
6772 * where
6773 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
6774 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
6775 * and solve it exactly under consideration of the fixing.
6776 */
6777 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
6778
6779 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
6780 for( j = 0; j < nitems; j++ )
6781 {
6782 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
6783
6784 if( snf->transvarcoefs[items[j]] == 1 )
6785 {
6786 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
6787 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6788 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6789 }
6790 else
6791 {
6792 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
6793 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6794 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6795 }
6796 }
6797 /* get capacity of knapsack constraint in KP^SNF_rat */
6798 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight; /*lint !e644*/
6799 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
6801
6802 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
6803 * is less than or equal to zero
6804 */
6805 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
6806 {
6807 assert(!(*found));
6808 goto TERMINATE;
6809 }
6810
6811 /* KP^SNF_rat has been solved by fixing some variables in advance */
6812 assert(nitems >= 0);
6813 if( nitems == 0 )
6814 {
6815 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6817 *lambda = QUAD_TO_DBL(flowcoverweight);
6818 *found = TRUE;
6819 goto TERMINATE;
6820 }
6821
6822 /* Solve the KP^SNF_rat approximately */
6823
6824 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
6825 nsolitems = -1;
6826 nnonsolitems = -1;
6827
6828 /* suitable factor C was found*/
6829 /* solve KP^SNF_rat approximately */
6832
6833 assert(nsolitems != -1);
6834 assert(nnonsolitems != -1);
6835
6836 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
6838 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6840 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6841
6842 *found = SCIPisFeasGT(scip, *lambda, 0.0);
6843
6844 TERMINATE:
6845 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
6846#ifdef SCIP_DEBUG
6847 if( *found )
6848 {
6849 SCIPdebugMsg(scip, "2. approximate solution:\n");
6850 for( j = 0; j < snf->ntransvars; j++ )
6851 {
6852 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
6853 {
6854 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6855 }
6856 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
6857 {
6858 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6859 }
6860 }
6861 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
6862 }
6863#endif
6864
6865 /* free data structures */
6873
6874 return SCIP_OKAY;
6875}
6876
6877#endif
6878
6879/** evaluate the super-additive lifting function for the lifted simple generalized flowcover inequalities
6880 * for a given value \f$ x \in \{ u_j \mid j \in C- \} \f$.
6881 */
6882static
6884 SCIP* scip, /**< SCIP data structure */
6885 LIFTINGDATA* liftingdata, /**< lifting data to use */
6886 SCIP_Real x /**< value where to evaluate lifting function */
6887 )
6888{
6889 SCIP_Real QUAD(tmp);
6890 SCIP_Real xpluslambda;
6891 int i;
6892
6893 assert( liftingdata != NULL );
6894
6895 xpluslambda = x + liftingdata->lambda;
6896
6897 i = 0;
6899 ++i;
6900
6901 if( i < liftingdata->t )
6902 {
6903 if( SCIPisLE(scip, liftingdata->M[i], x) )
6904 {
6906 return i * liftingdata->lambda;
6907 }
6908
6910
6911 /* return x - liftingdata->M[i] + i * liftingdata->lambda */
6915 return QUAD_TO_DBL(tmp);
6916 }
6917
6918 if( i < liftingdata->r )
6919 {
6921
6922 /* p = liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml; */
6926
6927 /* p = MAX(0.0, p); */
6928 if( QUAD_HI(tmp) < 0.0 )
6929 {
6930 QUAD_ASSIGN(tmp, 0.0);
6931 }
6932
6935
6937 return i * liftingdata->lambda;
6938
6941 MAX(0.0, liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml)));
6942
6946 return QUAD_TO_DBL(tmp);
6947 }
6948
6950
6954 return QUAD_TO_DBL(tmp);
6955}
6956
6957/** computes
6958 * \f[
6959 * (\alpha_j, \beta_j) =
6960 * \begin{cases}
6961 * (0, 0) &\quad\text{if} M_i \leq u_j \leq M_{i+1} - \lambda \\
6962 * (1, M_i - i \lambda) &\quad\text{if} M_i − \lambda < u_j < M_i \\
6963 * \end{cases}
6964 * \f]
6965 */
6966static
6968 SCIP* scip, /**< SCIP data structure */
6969 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
6970 SCIP_Real vubcoef, /**< vub coefficient to get alpha and beta for */
6971 int* alpha, /**< get alpha coefficient for lifting */
6972 SCIP_Real* beta /**< get beta coefficient for lifting */
6973 )
6974{
6975 SCIP_Real vubcoefpluslambda;
6976 int i;
6977
6979
6980 i = 0;
6982 ++i;
6983
6984 if( SCIPisLT(scip, vubcoef, liftingdata->M[i]) )
6985 {
6986 SCIP_Real QUAD(tmp);
6988 *alpha = 1;
6989 SCIPquadprecProdDD(tmp, -i, liftingdata->lambda);
6991 *beta = QUAD_TO_DBL(tmp);
6992 }
6993 else
6994 {
6997 *alpha = 0;
6998 *beta = 0.0;
6999 }
7000}
7001
7002/** compute relevant data for performing the sequence independent lifting */
7003static
7005 SCIP* scip, /**< SCIP data structure */
7006 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
7007 int* transvarflowcoverstatus, /**< pointer to store whether non-binary var is in L2 (2) or not (-1 or 1) */
7008 SCIP_Real lambda, /**< lambda */
7009 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
7010 SCIP_Bool* valid /**< is the lifting data valid */
7011 )
7012{
7013 int i;
7014 SCIP_Real QUAD(tmp);
7015 SCIP_Real QUAD(sumN2mC2LE);
7016 SCIP_Real QUAD(sumN2mC2GT);
7017 SCIP_Real QUAD(sumC1LE);
7018 SCIP_Real QUAD(sumC2);
7019
7020#ifndef NDEBUG
7021 /* for debugging */
7022 liftingdata->m = NULL;
7023 liftingdata->M = NULL;
7024 liftingdata->lambda = SCIP_INVALID;
7025 liftingdata->t = 0;
7027#endif
7028
7029 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->m, snf->ntransvars) );
7030
7031 liftingdata->r = 0;
7032 QUAD_ASSIGN(sumN2mC2LE, 0.0);
7033 QUAD_ASSIGN(sumC1LE, 0.0);
7034 QUAD_ASSIGN(sumN2mC2GT, 0.0);
7035 QUAD_ASSIGN(sumC2, 0.0);
7036
7038
7039 *valid = FALSE;
7040
7041 for( i = 0; i < snf->ntransvars; ++i )
7042 {
7043 int s = (snf->transvarcoefs[i] + 1) + (transvarflowcoverstatus[i] + 1)/2;
7044
7045 switch(s)
7046 {
7047 case 0: /* var is in N2 \ C2 */
7048 assert(snf->transvarvubcoefs[i] >= 0.0);
7049 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == -1);
7050
7051 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7052 {
7053 SCIPquadprecSumQD(sumN2mC2GT, sumN2mC2GT, snf->transvarvubcoefs[i]);
7054 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
7055 }
7056 else
7057 {
7058 SCIPquadprecSumQD(sumN2mC2LE, sumN2mC2LE, snf->transvarvubcoefs[i]);
7059 }
7060 break;
7061 case 1: /* var is in C2 */
7062 assert(snf->transvarvubcoefs[i] > 0.0);
7063 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == 1);
7064
7065 SCIPquadprecSumQD(sumC2, sumC2, snf->transvarvubcoefs[i]);
7066 break;
7067 case 3: /* var is in C1 */
7068 assert(snf->transvarcoefs[i] == 1 && transvarflowcoverstatus[i] == 1);
7069 assert(snf->transvarvubcoefs[i] > 0.0);
7070
7071 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7072 {
7073 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
7074 liftingdata->mp = MIN(liftingdata->mp, snf->transvarvubcoefs[i]);
7075 }
7076 else
7077 {
7078 SCIPquadprecSumQD(sumC1LE, sumC1LE, snf->transvarvubcoefs[i]);
7079 }
7080 break;
7081 default:
7082 assert(s == 2);
7083 continue;
7084 }
7085 }
7086
7087 if( SCIPisInfinity(scip, liftingdata->mp) )
7088 {
7090 return SCIP_OKAY;
7091 }
7092
7094
7095 *valid = TRUE;
7096
7098 liftingdata->ml = MIN(lambda, QUAD_TO_DBL(tmp));
7099 SCIPquadprecSumQD(tmp, sumC2, snf->transrhs);
7104
7106
7107 /* compute M[i] = sum_{i \in [1,r]} m[i] where m[*] is sorted decreasingly and M[0] = 0 */
7108 QUAD_ASSIGN(tmp, 0.0);
7109 for( i = 0; i < liftingdata->r; ++i)
7110 {
7113 }
7114
7116
7118 assert(liftingdata->m[liftingdata->t] == liftingdata->mp || SCIPisInfinity(scip, liftingdata->mp)); /*lint !e777*/
7119
7120 /* compute t largest index sucht that m_t = mp
7121 * note that liftingdata->m[t-1] == mp due to zero based indexing of liftingdata->m
7122 */
7123 ++liftingdata->t;
7124 while( liftingdata->t < liftingdata->r && liftingdata->m[liftingdata->t] == liftingdata->mp ) /*lint !e777*/
7125 ++liftingdata->t;
7126
7127 liftingdata->lambda = lambda;
7128
7129 return SCIP_OKAY;
7130}
7131
7132/** destroy data used for the sequence independent lifting */
7133static
7135 SCIP* scip, /**< SCIP data structure */
7136 LIFTINGDATA* liftingdata /**< pointer to lifting function struct */
7137 )
7138{
7141}
7142
7143/** store the simple lifted flowcover cut defined by the given data in the given arrays
7144 * the array for storing the cut coefficients must be all zeros
7145 */
7146static
7148 SCIP* scip, /**< SCIP data structure */
7149 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
7150 SCIP_AGGRROW* aggrrow, /**< aggrrow used to construct SNF relaxation */
7151 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
7152 SCIP_Real lambda, /**< lambda */
7153 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7154 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
7155 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7156 int* nnz, /**< number of non-zeros in cut */
7157 SCIP_Bool* success /**< was the cut successfully generated */
7158 )
7159{
7160 SCIP_Real QUAD(rhs);
7162 int i;
7163
7165 if( ! *success )
7166 return SCIP_OKAY;
7167 assert( liftingdata.m != NULL );
7168 assert( liftingdata.M != NULL );
7169 assert( liftingdata.lambda != SCIP_INVALID ); /*lint !e777*/
7170 assert( liftingdata.r >= 0 );
7171 assert( liftingdata.t >= 0 );
7172 assert( liftingdata.mp != SCIP_INVALID ); /*lint !e777*/
7173
7174 QUAD_ASSIGN(rhs, liftingdata.d1);
7175
7176 *nnz = 0;
7177
7178 for( i = 0; i < snf->ntransvars; ++i )
7179 {
7180 int s = (snf->transvarcoefs[i] + 1) + (flowcoverstatus[i] + 1)/2;
7181
7182 switch(s)
7183 {
7184 case 0: /* var is in N2 \ C2 */
7185 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7186 {
7187 /* var is in L- */
7188 if( snf->origbinvars[i] != -1 )
7189 {
7190 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7191 cutinds[*nnz] = snf->origbinvars[i];
7192 cutcoefs[snf->origbinvars[i]] = -lambda;
7193 ++(*nnz);
7194 }
7195 else
7196 {
7197 SCIPquadprecSumQD(rhs, rhs, lambda);
7198 }
7199 }
7200 else
7201 {
7202 /* var is in L-- */
7203 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7204 {
7205 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7206 cutinds[*nnz] = snf->origcontvars[i];
7207 cutcoefs[snf->origcontvars[i]] = -snf->aggrcoefscont[i];
7208 ++(*nnz);
7209 }
7210
7211 if( snf->origbinvars[i] != -1 && snf->aggrcoefsbin[i] != 0.0 )
7212 {
7213 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7214 cutinds[*nnz] = snf->origbinvars[i];
7215 cutcoefs[snf->origbinvars[i]] = -snf->aggrcoefsbin[i];
7216 ++(*nnz);
7217 }
7218
7219 SCIPquadprecSumQD(rhs, rhs, snf->aggrconstants[i]);
7220 }
7221 break;
7222 case 1: /* var is in C2 */
7223 {
7224 assert(snf->transvarvubcoefs[i] > 0.0);
7225 assert(snf->transvarcoefs[i] == -1 && flowcoverstatus[i] == 1);
7226
7227 if( snf->origbinvars[i] != -1 )
7228 {
7229 SCIP_Real liftedbincoef = evaluateLiftingFunction(scip, &liftingdata, snf->transvarvubcoefs[i]);
7230 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7231 if( liftedbincoef != 0.0 )
7232 {
7233 cutinds[*nnz] = snf->origbinvars[i];
7234 cutcoefs[snf->origbinvars[i]] = -liftedbincoef;
7235 ++(*nnz);
7236 SCIPquadprecSumQD(rhs, rhs, -liftedbincoef);
7237 }
7238 }
7239 break;
7240 }
7241 case 2: /* var is in N1 \ C1 */
7242 {
7243 int alpha;
7244 SCIP_Real beta;
7245
7246 assert(snf->transvarcoefs[i] == 1 && flowcoverstatus[i] == -1);
7247
7248 getAlphaAndBeta(scip, &liftingdata, snf->transvarvubcoefs[i], &alpha, &beta);
7249 assert(alpha == 0 || alpha == 1);
7250
7251 if( alpha == 1 )
7252 {
7253 SCIP_Real QUAD(binvarcoef);
7254 assert(beta > 0.0);
7255
7256 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7257 {
7258 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7259 cutinds[*nnz] = snf->origcontvars[i];
7260 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
7261 ++(*nnz);
7262 }
7263
7264 SCIPquadprecSumDD(binvarcoef, snf->aggrcoefsbin[i], -beta);
7265 if( snf->origbinvars[i] != -1 )
7266 {
7267 SCIP_Real tmp;
7268
7269 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7270
7272 if( tmp != 0.0 )
7273 {
7274 cutinds[*nnz] = snf->origbinvars[i];
7275 cutcoefs[snf->origbinvars[i]] = tmp;
7276 ++(*nnz);
7277 }
7278 }
7279 else
7280 {
7281 SCIPquadprecSumQQ(rhs, rhs, -binvarcoef);
7282 }
7283
7284 SCIPquadprecSumQD(rhs, rhs, -snf->aggrconstants[i]);
7285 }
7286 break;
7287 }
7288 case 3: /* var is in C1 */
7289 {
7290 SCIP_Real bincoef = snf->aggrcoefsbin[i];
7291 SCIP_Real constant = snf->aggrconstants[i];
7292
7293 if( snf->origbinvars[i] != -1 && SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7294 {
7295 /* var is in C++ */
7296 SCIP_Real QUAD(tmp);
7297 SCIP_Real QUAD(tmp2);
7298
7299 SCIPquadprecSumDD(tmp, snf->transvarvubcoefs[i], -lambda);
7300
7301 SCIPquadprecSumQD(tmp2, tmp, constant);
7302 constant = QUAD_TO_DBL(tmp2);
7303
7306 }
7307
7308 if( snf->origbinvars[i] != -1 && bincoef != 0.0 )
7309 {
7310 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7311 cutinds[*nnz] = snf->origbinvars[i];
7312 cutcoefs[snf->origbinvars[i]] = bincoef;
7313 ++(*nnz);
7314 }
7315
7316 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7317 {
7318 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7319 cutinds[*nnz] = snf->origcontvars[i];
7320 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
7321 ++(*nnz);
7322 }
7323
7324 SCIPquadprecSumQD(rhs, rhs, -constant);
7325 break;
7326 }
7327 default:
7328 SCIPABORT();
7329 }
7330 }
7331
7333
7334 {
7335 SCIP_ROW** rows = SCIPgetLPRows(scip);
7336 for( i = 0; i < aggrrow->nrows; ++i )
7337 {
7338 SCIP_ROW* row;
7339 SCIP_Real rowlhs;
7340 SCIP_Real rowrhs;
7341 SCIP_Real slackub;
7342 SCIP_Real slackcoef;
7343
7344 slackcoef = aggrrow->rowweights[i] * aggrrow->slacksign[i];
7345 assert(slackcoef != 0.0);
7346
7347 /* positive slack was implicitly handled in flow cover separation */
7348 if( slackcoef > 0.0 )
7349 continue;
7350
7351 row = rows[aggrrow->rowsinds[i]];
7352
7353 /* add the slack's definition multiplied with its coefficient to the cut */
7354 SCIP_CALL( varVecAddScaledRowCoefs(cutinds, cutcoefs, nnz, row, -aggrrow->rowweights[i]) );
7355
7356 /* retrieve sides of row */
7357 rowlhs = row->lhs - row->constant;
7358 rowrhs = row->rhs - row->constant;
7359
7360 if( row->integral )
7361 {
7364 }
7365
7366 slackub = rowrhs - rowlhs;
7367
7368 /* move slack's constant to the right hand side, and add lambda to the right hand side if the
7369 * upper bound of the slack is larger than lambda, since then an artifical binary variable
7370 * for the slack would get coefficient -lambda
7371 */
7372 if( aggrrow->slacksign[i] == +1 )
7373 {
7374 SCIP_Real rhsslack;
7375 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7376 assert(!SCIPisInfinity(scip, row->rhs));
7377
7379 slackub = -aggrrow->rowweights[i] * MIN(rhsslack, slackub);
7380
7381 if( SCIPisGE(scip, slackub, lambda) )
7382 SCIPquadprecSumQD(rhs, rhs, lambda);
7383
7384 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowrhs);
7385 }
7386 else
7387 {
7388 SCIP_Real lhsslack;
7389 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7390 assert(!SCIPisInfinity(scip, -row->lhs));
7391
7393 slackub = aggrrow->rowweights[i] * MIN(lhsslack, slackub);
7394
7395 if( SCIPisGE(scip, slackub, lambda) )
7396 SCIPquadprecSumQD(rhs, rhs, lambda);
7397
7398 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowlhs);
7399 }
7400 }
7401 }
7402
7403 *cutrhs = QUAD_TO_DBL(rhs);
7404
7405 /* relax rhs to zero, if it's very close to 0 */
7407 *cutrhs = 0.0;
7408
7409 return SCIP_OKAY;
7410}
7411
7412/** calculates a lifted simple generalized flow cover cut out of the weighted sum of LP rows given by an aggregation row; the
7413 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
7414 * participate in the cut.
7415 * For further details we refer to:
7416 *
7417 * Gu, Z., Nemhauser, G. L., & Savelsbergh, M. W. (1999). Lifted flow cover inequalities for mixed 0-1 integer programs.
7418 * Mathematical Programming, 85(3), 439-467.
7419 *
7420 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7421 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7422 *
7423 * @pre This method can be called if @p scip is in one of the following stages:
7424 * - \ref SCIP_STAGE_SOLVING
7425 *
7426 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
7427 */
7429 SCIP* scip, /**< SCIP data structure */
7430 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7431 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
7432 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
7433 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7434 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
7435 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
7436 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
7437 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
7438 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
7439 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
7440 int* cutrank, /**< pointer to return rank of generated cut */
7441 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
7442 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
7443 )
7444{
7445 int i;
7446 int nvars;
7447 SCIP_Bool localbdsused;
7449 SCIP_Real lambda;
7450 SCIP_Real* tmpcoefs;
7452 int nflowcovervars;
7454
7456
7457 *success = FALSE;
7458
7459 /* get data structures */
7462
7463 SCIPdebug( printCutQuad(scip, sol, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, FALSE, aggrrow->local) );
7464
7465 SCIP_CALL( constructSNFRelaxation(scip, sol, boundswitch, allowlocal, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, &snf, success, &localbdsused) );
7466
7467 if( ! *success )
7468 {
7469 goto TERMINATE;
7470 }
7471
7472 *cutislocal = aggrrow->local || localbdsused;
7473
7474 /* initialize lambda because gcc issues a stupid warning */
7475 lambda = 0.0;
7477
7478 if( ! *success )
7479 {
7480 goto TERMINATE;
7481 }
7482
7484
7486 SCIPdebugMsg(scip, "computed flowcover_%lli_%i:\n", SCIPgetNLPs(scip), SCIPgetNCuts(scip));
7487
7488 /* if success is FALSE generateLiftedFlowCoverCut wont have touched the tmpcoefs array so we dont need to clean it then */
7489 if( *success )
7490 {
7491 if( postprocess )
7492 {
7494 }
7495 else
7496 {
7497 SCIP_Real QUAD(rhs);
7498
7499 QUAD_ASSIGN(rhs, *cutrhs);
7501 *cutrhs = QUAD_TO_DBL(rhs);
7502 }
7503
7504 if( *success )
7505 {
7506 /* store cut sparse and calculate efficacy */
7507 for( i = 0; i < *cutnnz; ++i )
7508 {
7509 int j = cutinds[i];
7510 assert(tmpcoefs[j] != 0.0);
7511 cutcoefs[i] = tmpcoefs[j];
7512 tmpcoefs[j] = 0.0;
7513 }
7514
7515 if( cutefficacy != NULL )
7517
7518 if( cutrank != NULL )
7519 *cutrank = aggrrow->rank + 1;
7520 }
7521 else
7522 {
7523 /* clean buffer array */
7524 for( i = 0; i < *cutnnz; ++i )
7525 {
7526 int j = cutinds[i];
7527 assert(tmpcoefs[j] != 0.0);
7528 tmpcoefs[j] = 0.0;
7529 }
7530 }
7531 }
7532
7534
7535 TERMINATE:
7538
7539 return SCIP_OKAY;
7540}
7541
7542/* =========================================== knapsack cover =========================================== */
7543
7544/** Relax the row to a possibly fractional knapsack row containing no integer or continuous variables
7545 * and only having positive coefficients for binary variables. General integer and continuous variables
7546 * are complemented with variable or simple bounds such that their coefficient becomes positive and then
7547 * it is relaxed to zero.
7548 * All remaining binary variables are complemented with simple upper or lower bounds such that their
7549 * coefficient becomes positive.
7550 */
7551static
7553 SCIP* scip, /**< SCIP data structure */
7554 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7555 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7556 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7557 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
7558 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7559 int* nnz, /**< number of non-zeros in cut */
7560 int* varsign, /**< stores the sign of the transformed variable in summation */
7561 int* boundtype, /**< stores the bound used for transformed variable:
7562 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
7563 SCIP_Bool* localbdsused, /**< pointer to store whether local bounds were used in transformation */
7564 SCIP_Bool* success /**< stores whether the row could successfully be transformed into a knapsack constraint.
7565 * Returns FALSE in case a continuous or general integer variable is unbounded in the
7566 * required direction. */
7567 )
7568{
7569 SCIP_Real* bestbds;
7570 int i;
7571 int aggrrowbinstart;
7572 int firstnonbinvar;
7573 SCIP_VAR** vars;
7574
7575 assert(varsign != NULL);
7576 assert(boundtype != NULL);
7577 assert(success != NULL);
7579
7580 *success = FALSE;
7581
7582 /* allocate temporary memory to store best bounds and bound types */
7584
7585 /* start with continuous variables, because using variable bounds can affect the untransformed binary
7586 * variables, and these changes have to be incorporated in the transformation of the binary variables
7587 * (binary variables have the smallest problem indices!)
7588 */
7589 SCIPsortDownInt(cutinds, *nnz);
7590
7593
7594 /* determine best bounds for the continuous and general integer variables such that they will have
7595 * a positive coefficient in the transformation */
7597 {
7598 SCIP_Real QUAD(coef);
7599 int v = cutinds[i];
7600
7601 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7602
7603 if( QUAD_TO_DBL(coef) > 0.0 )
7604 {
7605 SCIP_Real simplebound;
7606
7607 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable
7608 * so that it will have a positive coefficient */
7609 SCIP_CALL( findBestLb(scip, vars[v], sol, 1, allowlocal, bestbds + i, &simplebound, boundtype + i) );
7610
7611 /* cannot transform into knapsack */
7612 if( SCIPisInfinity(scip, -bestbds[i]) )
7613 goto TERMINATE;
7614
7615 varsign[i] = +1;
7616 }
7617 else if( QUAD_TO_DBL(coef) < 0.0 )
7618 {
7619 SCIP_Real simplebound;
7620
7621 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable
7622 * so that it will have a positive coefficient */
7623 SCIP_CALL( findBestUb(scip, vars[v], sol, 1, allowlocal, bestbds + i, &simplebound, boundtype + i) );
7624
7625 /* cannot transform into knapsack */
7626 if( SCIPisInfinity(scip, bestbds[i]) )
7627 goto TERMINATE;
7628
7629 varsign[i] = -1;
7630 }
7631 }
7632
7633 /* remember start of integer variables in the aggrrow */
7635
7636 /* perform bound substitution for continuous variables */
7637 for( i = 0; i < aggrrowbinstart; ++i )
7638 {
7639 SCIP_Real QUAD(coef);
7640 int v = cutinds[i];
7641
7643
7644 /* relax non-binary coefficient to zero after bound substitution */
7645 QUAD_ASSIGN(coef, 0.0);
7646 QUAD_ARRAY_STORE(cutcoefs, v, coef);
7647 }
7648
7650
7651 /* remove non-binary variables because their coefficients have been set to zero after bound substitution */
7652 if( aggrrowbinstart != 0 )
7653 {
7654 *nnz -= aggrrowbinstart;
7656 }
7657 i = 0;
7658
7659 /* after doing bound substitution of non-binary vars, some coefficients of binary vars might have changed, so here we
7660 * remove the ones that became 0 if any; also, we need that all remaining binary vars have positive coefficients,
7661 * thus we perform bound substitution with simple bounds (i.e. complementing) to achieve this.
7662 */
7663 while( i < *nnz )
7664 {
7665 SCIP_Real QUAD(coef);
7666 SCIP_Real simplebound;
7667 SCIP_Real bestlb;
7668 SCIP_Real bestub;
7669 SCIP_Bool setzero;
7670 int v = cutinds[i];
7671
7673
7675 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7676
7677 /* due to variable bound usage for bound substitution of continuous variables cancellation may have occurred */
7678 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
7679 {
7680 /* do not increase i, since last element is copied to the i-th position */
7681 setzero = TRUE;
7682 }
7683 else
7684 {
7685 /* perform bound substitution */
7686 if( QUAD_TO_DBL(coef) < 0.0 )
7687 {
7688 SCIP_CALL( findBestUb(scip, vars[v], sol, 0, allowlocal, &bestub, &simplebound, boundtype + i) );
7689
7690 if( SCIPisZero(scip, bestub) )
7691 {
7692 /* binary variable is fixed to zero */
7693 setzero = TRUE;
7694 *localbdsused = *localbdsused || (boundtype[i] == -2);
7695 }
7696 else
7697 {
7698 varsign[i] = -1;
7699
7701 QUAD_ARRAY_STORE(cutcoefs, v, -coef);
7702 setzero = FALSE;
7703 }
7704 }
7705 else
7706 {
7707 SCIP_CALL( findBestLb(scip, vars[v], sol, 0, allowlocal, &bestlb, &simplebound, boundtype + i) );
7708
7709 if( !SCIPisZero(scip, bestlb) )
7710 {
7711 /* binary variable is fixed to one */
7713 setzero = TRUE;
7714 }
7715 else
7716 {
7717 varsign[i] = +1;
7718 setzero = FALSE;
7719 }
7720 }
7721
7722 assert(boundtype[i] == -1 || boundtype[i] == -2);
7723 }
7724
7725 /* increase i or remove zero coefficient (i.e. var with 0 coef) by shifting last nonzero to current position */
7726 if( setzero )
7727 {
7728 QUAD_ASSIGN(coef, 0.0);
7729 QUAD_ARRAY_STORE(cutcoefs, v, coef);
7730 --(*nnz);
7731 cutinds[i] = cutinds[*nnz];
7732 }
7733 else
7734 ++i;
7735 }
7736
7737 /* relax rhs to zero if it is close to but slightly below zero */
7738 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
7739 QUAD_ASSIGN(*cutrhs, 0.0);
7740
7741 *success = TRUE;
7742 TERMINATE:
7743 /*free temporary memory */
7745
7746 return SCIP_OKAY;
7747}
7748
7749/** determines the initial cover for the given (fractional) knapsack row */
7750static
7752 SCIP* scip, /**< SCIP datastructure */
7753 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7754 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
7755 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
7756 SCIP_Real cutrhs, /**< pointer to the right hand side of the cut */
7757 int cutnnz, /**< pointer to the number of non-zeros in the cut */
7758 int* varsign, /**< sign of coefficients for each nonzero in the row be transformation */
7759 int* coverstatus, /**< array to return the coverstatus for each variable in the knapsack row */
7760 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
7761 SCIP_Real* covervals, /**< coefficient value of each variable in the cover */
7762 int* coversize, /**< pointer to return number of variables in the cover;
7763 * matches the length of the associated arrays */
7764 QUAD(SCIP_Real* coverweight) /**< pointer to return the weight of the cover;
7765 * the weight is the sum of the coefficient values of variables in the cover */
7766 )
7767{
7768 SCIP_VAR** vars;
7769 int k;
7770 int j;
7772 *coversize = 0;
7773 j = cutnnz-1;
7775
7776 for( k = 0; k < cutnnz; ++k )
7777 {
7778 SCIP_Real solval;
7779 int v = cutinds[k];
7780 SCIP_Real QUAD(coef);
7781 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7782
7783 solval = SCIPgetSolVal(scip, sol, vars[v]);
7784 if( varsign[k] == -1 )
7785 solval = 1 - solval;
7786
7787 if( SCIPisFeasEQ(scip, solval, 1.0) )
7788 {
7789 /* every variable with solution value 1 is forced into the cover */
7790 coverpos[*coversize] = k;
7792 coverstatus[k] = 1;
7793 *coversize += 1;
7795 }
7796 else
7797 {
7798 coverpos[j] = k;
7799 covervals[j] = solval * QUAD_TO_DBL(coef);
7800 coverstatus[k] = 0;
7801 j -= 1;
7802 }
7803 }
7804
7805 /* Use these two arrays to sort the variables by decreasing contribution
7806 * and pick them greedily in the while loop below until they are a cover.
7807 * Since the cover does not need to be minimal we do not need to remove any of the
7808 * variables with a high activity contribution even if they are not necessary after
7809 * picking the last variable.
7810 */
7812
7813 /* overwrite covervals with the coefficients of the variables in the cover
7814 * as we need to sort decreasingly by those again for the lifting
7815 */
7816 while( *coversize < cutnnz &&
7818 {
7819 int v;
7820 SCIP_Real QUAD(coef);
7821 k = coverpos[*coversize];
7822 v = cutinds[k];
7823 coverstatus[k] = 1;
7824 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7827 *coversize += 1;
7828 }
7829
7830 /* there is no cover */
7832 return FALSE;
7833
7834 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(*coverweight), cutrhs);
7835 assert(*coversize > 0);
7836
7837 return TRUE;
7838}
7839
7840/** prepares the data needed to evaluate the lifting function */
7841static
7843 SCIP* scip, /**< SCIP datastructure */
7844 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
7845 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
7846 QUAD(SCIP_Real cutrhs), /**< pointer to the right hand side of the cut */
7847 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
7848 int coversize, /**< number of variables in the cover */
7849 QUAD(SCIP_Real coverweight), /**< weight of cover */
7850 SCIP_Real* covervals, /**< coefficient value of each variable in the cover;
7851 * on output stores the running sum of S^-(*) values */
7852 int* coverstatus, /**< coverstatus for each variable in the cover. After calling this function
7853 * variables in C^- will have the value -1, variables in C^+ the value 1,
7854 * and all variables outside the cover keep the value 0. */
7855 QUAD(SCIP_Real* abar), /**< pointer to store the reciprocal value of \bar{a} */
7856 int* cplussize /**< pointer to store the size of C^+ */
7857 )
7858{
7859 int k;
7860 SCIP_Real QUAD(tmp);
7861 SCIP_Real QUAD(sigma);
7862
7863 /* Now compute \bar{a}, the unique rational number such that for the cover C it holds that
7864 * b = \sum_{a_i \in C} \min(\bar{a}, a_i).
7865 * For that we need to sort by decreasing coefficients of the variables in the cover.
7866 * After the sorting the covervals array is free to be reused.
7867 */
7869
7870 /* Now follows Algorithm 1 in the paper to compute \bar{a} */
7871
7872 /* set \bar{a} = l_1 */
7875
7876 for( k = 1; k < coversize; ++k )
7877 {
7878 SCIP_Real QUAD(lkplus1);
7879 SCIP_Real QUAD(kdelta);
7880
7881 /* load next coefficient l_{k+1} in sorted order of cover */
7883
7884 /* Let \delta = \bar{a} - l_{k+1} and compute k * \delta */
7887
7888 /* Set tmp = k * \delta - \sigma to check condition k * \delta < \sigma by tmp < 0 */
7889 SCIPquadprecSumQQ(tmp, kdelta, -sigma);
7890 if( QUAD_TO_DBL(tmp) < 0.0 )
7891 {
7892 /* Set \bar{a} = l_{k+1} and \sigma = \sigma - k*\delta */
7894 SCIPquadprecSumQQ(sigma, sigma, -kdelta);
7895 }
7896 else
7897 {
7898 /* Set \bar{a} = \bar{a} - \sigma / k and \sigma = 0; break; */
7899 SCIP_Real minusoneoverk = -1.0 / k;
7900 SCIPquadprecProdQD(sigma, sigma, minusoneoverk);
7901 SCIPquadprecSumQQ(*abar, *abar, sigma);
7902 QUAD_ASSIGN(sigma, 0.0);
7903 break;
7904 }
7905 }
7906
7907 if( QUAD_TO_DBL(sigma) > 0.0 )
7908 {
7909 SCIP_Real oneoverc = 1.0 / coversize;
7911 }
7912
7913 /* now we partition C into C^+ and C^-, where C^+ are all the elements of C whose weight is strictly larger than
7914 * \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
7915 * compute S^-(h) = sum of the h largest a_i^- and store S^-(h+1) in in covervals[h], for k = 0, ..., coversize - 1
7916 * (S^-(0) = 0 so it doesn't need to be stored; we use S to compute the lifted cut, see below)
7917 * we remember which elements of C^- in coverstatus, so that element in C^+ have coverstatus 1 and
7918 * elements in C^- have coverstatus -1 (elements not in C have coverstatus 0)
7919 */
7920 QUAD_ASSIGN(tmp, 0.0);
7921 *cplussize = 0;
7922 for( k = 0; k < coversize; ++k )
7923 {
7924 SCIP_Real QUAD(coef);
7925 SCIP_Real QUAD(coefminusabar);
7926
7929 if( QUAD_TO_DBL(coefminusabar) > 0.0 )
7930 {
7931 /* coefficient is in C^+ because it is greater than \bar{a} and contributes only \bar{a} to the sum */
7933
7934 /* rather be on the safe side in numerical corner cases and relax the coefficient to exactly \bar{a}.
7935 * In that case the coefficient is not treated as in C^+ but as being <= \bar{a} and therefore in C^-.
7936 */
7938 ++(*cplussize);
7939 else
7940 coverstatus[coverpos[k]] = -1;
7941 }
7942 else
7943 {
7944 /* coefficient is in C^- because it is smaller or equal to \bar{a} */
7945 coverstatus[coverpos[k]] = -1;
7946 SCIPquadprecSumQQ(tmp, tmp, coef);
7947 }
7949 SCIPdebugMsg(scip, "S^-(%d) = %g\n", k + 1, covervals[k]);
7950 }
7951
7952 /* set abar to its reciprocal for faster computation of the lifting coefficients */
7954}
7955
7956/** evaluate the lifting function based on the given values */
7957static
7959 SCIP* scip, /**< SCIP datastructure */
7960 QUAD(SCIP_Real x), /**< value to evaluate the lifting function at */
7961 QUAD(SCIP_Real abar), /**< the reciprocal value of \bar{a} */
7962 SCIP_Real* covervals, /**< the running sum of S^-(*) values */
7963 int coversize, /**< the size of the cover */
7964 int cplussize, /**< the size of C^+ */
7965 SCIP_Real* scale /**< pointer to update the scale to integrality when a fractional value is returned */
7966 )
7967{
7968 SCIP_Real QUAD(tmp);
7969 SCIP_Real QUAD(hfrac);
7970 SCIP_Real cutcoef;
7971 SCIP_Real hreal;
7972 int h;
7973
7974 /* the lifted value is at least the coeficient (a_k) divided by \bar{a} because the largest value
7975 * contributed to the running sum stored in C is \bar{a}
7976 * therefore we start the search for the correct h at floor(a_k / \bar{a})
7977 */
7978
7979 SCIPdebugMsg(scip, "coef is %g, coversize is %d\n", QUAD_TO_DBL(x), coversize );
7980
7982
7983 /* if the coefficient is below \bar{a}, i.e. a / \bar{a} < 1 then g(a_k) = 0, otherwise g(a_k) > 0 */
7984 if( QUAD_TO_DBL(hfrac) < 1 )
7985 return 0.0;
7986
7987 /* we perform h = MIN(h, coversize) in floating-point first because on some instances h was seen to exceed the range
7988 * of int */
7990 if( hreal > (SCIP_Real)coversize )
7991 h = coversize;
7992 else
7993 h = (int)hreal;
7994
7996
7997 assert(h > 0);
7999 {
8000 /* cutcoef can be increased by 0.5 because it is a multiple of \bar{a}
8001 * (This is the first non-dominated lifting function presented in the paper)
8002 */
8003 cutcoef = 0.5;
8004 *scale = 2.0;
8005 }
8006 else
8007 cutcoef = 0.0;
8008
8009 /* decrease by one to make sure rounding errors or coefficients that are larger than the right hand side by themselves
8010 * did not push h too far */
8011 h--;
8012
8013 /* now increase coefficient to its lifted value based on its size relative to the S^- values.
8014 * The coefficient a_i is lifted to the unique integer h such that S^-(h) < a_i <= S^-(h+1).
8015 * (todo: variables that have a coefficient above the right hand side can get an arbitrarily large coefficient but can
8016 * also be trivially fixed using the base row. Currently they get the coefficient |C| which is 1 above the right hand
8017 * side in the cover cut so that they can still be trivially fixed by propagating the cover cut.
8018 * We do not want to apply fixings here though because the LP should stay flushed during separation.
8019 * Possibly add a parameter to return additional fixings to the caller of the SCIPcalc*() functions in here
8020 * and the caller can add them as cuts to the sepastore or we add them to the sepastore here?)
8021 */
8022 while( h < coversize )
8023 {
8024 SCIPquadprecSumQD(tmp, x, -covervals[h]); /* recall: covervals[h] = S^-(h+1) */
8025 /* compare to an increased epsilon since computation involves abar, which is computed like an activity */
8026 if( QUAD_TO_DBL(tmp) <= 1000.0*QUAD_EPSILON )
8027 break;
8028
8029 ++h;
8030 }
8031
8032 cutcoef += h;
8033
8034 SCIPdebugMsg(scip, "x is %g, coversize is %d, h is %d\n", QUAD_TO_DBL(x), coversize, h );
8035 /* the lifted coefficient is h increased possibly by 0.5 for the case checked above */
8036 SCIPdebugMsg(scip, "lifted coef %g < %g <= %g to %g\n", h == 0 ? 0 : covervals[h-1], QUAD_TO_DBL(x),
8037 covervals[h], cutcoef);
8038
8039 return cutcoef;
8040}
8041
8042/** calculates a lifted knapsack cover cut out of the weighted sum of LP rows given by an aggregation row; the
8043 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
8044 * participate in the cut.
8045 * For further details we refer to:
8046 *
8047 * Letchford, A. N., & Souli, G. (2019). On lifted cover inequalities: A new lifting procedure with unusual properties.
8048 * Operations Research Letters, 47(2), 83-87.
8049 *
8050 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8051 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8052 *
8053 * @pre This method can be called if @p scip is in one of the following stages:
8054 * - \ref SCIP_STAGE_SOLVING
8055 *
8056 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
8057 */
8059 SCIP* scip, /**< SCIP data structure */
8060 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8061 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8062 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
8063 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
8064 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
8065 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
8066 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
8067 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
8068 int* cutrank, /**< pointer to return rank of generated cut */
8069 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
8070 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
8071 )
8072{
8073 int* varsign;
8074 int* boundtype;
8075 int* coverstatus;
8076 int* coverpos;
8077 int* tmpinds;
8078 SCIP_Real* tmpcoefs;
8079 SCIP_Real* covervals;
8080 SCIP_Real QUAD(rhs);
8081 SCIP_Real QUAD(coverweight);
8082 SCIP_Real QUAD(abar);
8083 SCIP_Bool transformed;
8084 SCIP_Bool local;
8085 SCIP_Real efficacy;
8086 SCIP_Real scale;
8087 int k;
8088 int nvars;
8089 int coversize;
8090 int cplussize;
8091 int nnz;
8092
8093 assert(scip != NULL);
8094 assert(aggrrow != NULL);
8095 assert(cutcoefs != NULL);
8096 assert(cutrhs != NULL);
8097 assert(cutinds != NULL);
8098 assert(cutnnz != NULL);
8101 assert(success != NULL);
8102
8103 *success = FALSE;
8104
8105 if( aggrrow->nnz == 0 )
8106 return SCIP_OKAY;
8107
8108 for( k = 0; k < aggrrow->nrows; ++k )
8109 {
8110 /* cannot handle negative slack variables */
8111 if( aggrrow->rowweights[k] * aggrrow->slacksign[k] < 0 )
8112 return SCIP_OKAY;
8113 }
8114
8115 /* allocate temporary memory */
8118 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
8124
8125 /* initialize cut with aggregation */
8126 nnz = aggrrow->nnz;
8127 QUAD_ASSIGN_Q(rhs, aggrrow->rhs);
8128
8129 BMScopyMemoryArray(tmpinds, aggrrow->inds, nnz);
8130
8131 for( k = 0; k < nnz; ++k )
8132 {
8133 SCIP_Real QUAD(coef);
8134 int j = tmpinds[k];
8135
8136 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
8137
8138 QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
8139 assert(QUAD_HI(coef) != 0.0);
8140
8141 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
8142 }
8143 SCIPdebugMsg(scip, "Computing lifted knapsack cover for ");
8145
8146 /* Transform aggregated row into a (fractional, i.e. with possibly fractional weights) knapsack constraint.
8147 * Uses simple or variable lower or upper bounds to relax out continuous and general integers
8148 * so that only binary variables remain and complements those such that they have a positive coefficient.
8149 */
8150 local = aggrrow->local;
8152 tmpcoefs, QUAD(&rhs), tmpinds, &nnz, varsign, boundtype, &local, &transformed) );
8153
8154 assert(allowlocal || !local);
8155
8156 if( !transformed )
8157 goto TERMINATE;
8158
8159 SCIPdebugMsg(scip, "Transformed knapsack relaxation ");
8161
8164 goto TERMINATE;
8165
8166 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(coverweight), QUAD_TO_DBL(rhs));
8167 assert(coversize > 0);
8168
8169 /* by default do not scale the cut */
8170 scale = 1.0;
8171
8172 if( coversize == 1 )
8173 {
8174 SCIP_Real QUAD(tmp);
8175 /* cover is trivial, return the fixing as cut */
8176 QUAD_ASSIGN(tmp, 0.0);
8177 for( k = 0; k < nnz; ++k )
8178 {
8179 if( coverstatus[k] == 0 )
8180 {
8182 }
8183 else
8184 {
8185 tmpinds[0] = tmpinds[k];
8186 varsign[0] = varsign[k];
8187 }
8188 }
8189
8190 nnz = 1;
8191 if( varsign[0] == -1 )
8192 {
8193 QUAD_ASSIGN(rhs, -1.0);
8194 QUAD_ASSIGN(tmp, -1.0);
8195 }
8196 else
8197 {
8198 QUAD_ASSIGN(rhs, 0.0);
8199 QUAD_ASSIGN(tmp, 1.0);
8200 }
8201
8203 }
8204 else
8205 {
8206 SCIP_Real QUAD(tmp);
8207
8208 /* compute lifted cover inequality:
8209 * sum_{i \in C^-) x_i + sum_{i \in N \ C^-) g(a_i) x_i <= c - 1
8210 * where g(z) is equal to
8211 * - 0 if z is 0 (irrelevant as there shouldn't be element with weight 0 in the knapsack)
8212 * - 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
8213 * - h if S^-(h) < z <= S^-(h+1) for some h = 0, ..., coversize -1
8214 * the function S^- is defined above. Note that S^-(0) = 0
8215 * we store the cut coefficients in tmpcoef
8216 */
8217
8218 SCIPdebugMsg(scip, "call prepareLiftingData: \n");
8219 /* prepare data required to evaluate lifting function */
8222
8223 /* compute lifted cover inequality */
8224 QUAD_ASSIGN(rhs, (coversize - 1));
8225 for( k = 0; k < nnz; )
8226 {
8227 SCIP_Real cutcoef;
8228 if( coverstatus[k] == -1 )
8229 { /* variables in C^- get the coefficients 1 */
8230 cutcoef = 1.0;
8231 }
8232 else
8233 { /* variables is either in C^+ or not in the cover and its coefficient value is computed with the lifing function */
8234 SCIP_Real QUAD(coef);
8235
8236 SCIPdebugMsg(scip, "load QUAD(coef) from tmpcoefs[tmpinds[k] = %d]\n",tmpinds[k]);
8238
8239 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));
8240
8241 SCIPdebugMsg(scip, "call evaluateLiftingFunctionKnapsack:\n");
8243
8244 /* if the coefficient value is zero then remove the nonzero entry and continue */
8245 if( cutcoef == 0.0 )
8246 {
8247 QUAD_ASSIGN(tmp, 0.0);
8249 --nnz;
8250 coverstatus[k] = coverstatus[nnz];
8251 tmpinds[k] = tmpinds[nnz];
8252 varsign[k] = varsign[nnz];
8253 continue;
8254 }
8255 }
8256
8257 /* directly undo the complementation before storing back the coefficient */
8258 if( varsign[k] == -1 )
8259 {
8260 /* variable was complemented so we have cutcoef * (1-x) = cutcoef - cutcoef * x.Thus we need to adjust the rhs
8261 * to rhs - cutcoef and flip the sign of cutcoef */
8262 cutcoef = -cutcoef;
8263 SCIPquadprecSumQD(rhs, rhs, cutcoef);
8264 }
8265
8268
8269 ++k;
8270 }
8271 }
8272
8273 /* calculate the efficacy of the computed cut and store the success flag if the efficacy exceeds the
8274 * one stored in the cutefficacy variable by the caller
8275 */
8278
8279 SCIPdebugMsg(scip, "FINAL LCI:");
8281
8282 if( *success )
8283 {
8284 /* return the cut into the given arrays/pointers */
8285 *cutislocal = local;
8286 *cutrhs = scale * QUAD_TO_DBL(rhs);
8287 *cutnnz = nnz;
8288
8289 /* store cut in given array in sparse representation and clean buffer array */
8290 for( k = 0; k < nnz; ++k )
8291 {
8292 SCIP_Real QUAD(coef);
8293 int j = tmpinds[k];
8294
8295 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
8296 assert(QUAD_HI(coef) != 0.0);
8297
8298 cutcoefs[k] = scale * QUAD_TO_DBL(coef);
8299 cutinds[k] = j;
8300 QUAD_ASSIGN(coef, 0.0);
8301 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
8302 }
8303
8304 assert( cutefficacy != NULL );
8305 /* calculate efficacy again to make sure it matches the coefficients after they where rounded to double values
8306 * and after the cleanup and postprocessing step was applied. */
8308
8309 if( cutrank != NULL )
8310 *cutrank = aggrrow->rank + 1;
8311 }
8312
8313 TERMINATE:
8314
8315 /* if we aborted early the tmpcoefs array needs to be cleaned */
8316 if( !(*success) )
8317 {
8318 SCIP_Real QUAD(tmp);
8319 QUAD_ASSIGN(tmp, 0.0);
8320
8321 for( k = 0; k < nnz; ++k )
8322 {
8324 }
8325 }
8326#ifndef NDEBUG
8327 for( k = 0; k < QUAD_ARRAY_SIZE(nvars); ++k )
8328 {
8329 if(tmpcoefs[k] != 0.0)
8330 {
8331 SCIPdebugMsg(scip, "tmpcoefs have not been reset\n");
8332 SCIPABORT();
8333 }
8334 }
8335#endif
8336
8337 /* free temporary memory */
8343 SCIPfreeBufferArray(scip, &boundtype);
8345
8346 return SCIP_OKAY;
8347}
8348
8349
8350/* =========================================== strongcg =========================================== */
8351
8352/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
8353 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
8354 *
8355 * Differs from cutsTransformMIR for continuous variables for which the lower bound must be used
8356 * when in case their coefficient is positive and the upper bound in case their coefficient is
8357 * negative. This forces all continuous variable to have a positive coefficient in the transformed
8358 * row.
8359 *
8360 * Transform variables (lb or ub):
8361 * \f[
8362 * \begin{array}{llll}
8363 * 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}\\
8364 * 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}
8365 * \end{array}
8366 * \f]
8367 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
8368 *
8369 * Transform variables (vlb or vub):
8370 * \f[
8371 * \begin{array}{llll}
8372 * 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.} \\
8373 * 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.}
8374 * \end{array}
8375 * \f]
8376 * 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:
8377 * \f[
8378 * \begin{array}{ll}
8379 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
8380 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
8381 * \end{array}
8382 * \f]
8383 */
8384static
8386 SCIP* scip, /**< SCIP data structure */
8387 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8388 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
8389 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
8390 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8391 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8392 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8393 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8394 int* nnz, /**< number of non-zeros in cut */
8395 int* varsign, /**< stores the sign of the transformed variable in summation */
8396 int* boundtype, /**< stores the bound used for transformed variable:
8397 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
8398 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
8399 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
8400 )
8401{
8402 SCIP_Real* bestbds;
8403 int i;
8404 int aggrrowintstart;
8405 int nvars;
8406 int firstcontvar;
8407 SCIP_VAR** vars;
8408
8409 assert(varsign != NULL);
8410 assert(boundtype != NULL);
8413
8416
8417 /* allocate temporary memory to store best bounds and bound types */
8419
8420 /* start with continuous variables, because using variable bounds can affect the untransformed integral
8421 * variables, and these changes have to be incorporated in the transformation of the integral variables
8422 * (continuous variables have largest problem indices!)
8423 */
8424 SCIPsortDownInt(cutinds, *nnz);
8425
8429
8430 /* determine best bounds for the continuous variables such that they will have a positive coefficient in the transformation */
8432 {
8433 SCIP_Real QUAD(coef);
8434 int v = cutinds[i];
8435
8436 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
8437
8438 if( QUAD_TO_DBL(coef) > 0.0 )
8439 {
8440 SCIP_Real simplebound;
8441
8442 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
8443 SCIP_CALL( findBestLb(scip, vars[v], sol, usevbds ? 2 : 0, allowlocal, bestbds + i, &simplebound, boundtype + i) );
8444
8445 /* cannot create transformation for strongcg cut */
8446 if( SCIPisInfinity(scip, -bestbds[i]) )
8447 {
8448 *freevariable = TRUE;
8449 goto TERMINATE;
8450 }
8451
8452 varsign[i] = +1;
8453 }
8454 else if( QUAD_TO_DBL(coef) < 0.0 )
8455 {
8456 SCIP_Real simplebound;
8457
8458 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
8459 SCIP_CALL( findBestUb(scip, vars[v], sol, usevbds ? 2 : 0, allowlocal, bestbds + i, &simplebound, boundtype + i) );
8460
8461 /* cannot create transformation for strongcg cut */
8462 if( SCIPisInfinity(scip, bestbds[i]) )
8463 {
8464 *freevariable = TRUE;
8465 goto TERMINATE;
8466 }
8467
8468 varsign[i] = -1;
8469 }
8470 }
8471
8472 /* remember start of integer variables in the aggrrow */
8474
8475 /* perform bound substitution for continuous variables */
8476 for( i = 0; i < aggrrowintstart; ++i )
8477 {
8479 }
8480
8482
8483 /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
8484 * and perform the bound substitution for the integer variables that are left using simple bounds
8485 */
8486 while( i < *nnz )
8487 {
8488 SCIP_Real QUAD(coef);
8489 SCIP_Real bestlb;
8490 SCIP_Real bestub;
8491 int bestlbtype;
8492 int bestubtype;
8494 int v = cutinds[i];
8495
8496 assert(v < firstcontvar);
8497 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
8498
8499 /* due to variable bound usage for the continuous variables cancellation may have occurred */
8500 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
8501 {
8502 QUAD_ASSIGN(coef, 0.0);
8503 QUAD_ARRAY_STORE(cutcoefs, v, coef);
8504 --(*nnz);
8505 cutinds[i] = cutinds[*nnz];
8506
8507 /* do not increase i, since last element is copied to the i-th position */
8508 continue;
8509 }
8510
8511 /* determine the best bounds for the integral variable, usevbd can be set to 0 here as vbds are only used for continuous variables */
8514
8515 /* check if we have an unbounded integral variable */
8516 if( *freevariable )
8517 {
8518 goto TERMINATE;
8519 }
8520
8521 /* perform bound substitution */
8523 {
8524 boundtype[i] = bestlbtype;
8525 varsign[i] = +1;
8526
8528 }
8529 else
8530 {
8532 boundtype[i] = bestubtype;
8533 varsign[i] = -1;
8534
8536 }
8537
8538 assert(boundtype[i] == -1 || boundtype[i] == -2);
8539
8540 /* increase i */
8541 ++i;
8542 }
8543
8544 /* relax rhs to zero if it is close to */
8545 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
8546 QUAD_ASSIGN(*cutrhs, 0.0);
8547
8548 TERMINATE:
8549 /* free temporary memory */
8551
8552 return SCIP_OKAY;
8553}
8554
8555/** Calculate fractionalities \f$ f_0 := b - down(b) \f$, \f$ f_j := a^\prime_j - down(a^\prime_j) \f$,
8556 * 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
8557 * 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$
8558 * and derive strong CG cut \f$ \tilde{a} x^\prime \leq down(b) \f$
8559 * \f[
8560 * \begin{array}{rll}
8561 * integers : & \tilde{a}_j = down(a^\prime_j) &, if \qquad f_j \leq f_0 \\
8562 * & \tilde{a}_j = down(a^\prime_j) + p_j/(k + 1) &, if \qquad f_j > f_0 \\
8563 * continuous:& \tilde{a}_j = 0 &, if \qquad a^\prime_j \geq 0 \\
8564 * & \mbox{no strong CG cut found} &, if \qquad a^\prime_j < 0
8565 * \end{array}
8566 * \f]
8567 *
8568 * Transform inequality back to \f$ \hat{a}*x <= rhs \f$:
8569 *
8570 * (lb or ub):
8571 * \f[
8572 * \begin{array}{lllll}
8573 * 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} \\
8574 * 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}
8575 * \end{array}
8576 * \f]
8577 * \f[
8578 * and move the constant terms
8579 * \begin{array}{rl}
8580 * -\tilde{a}_j * lb_j == -\hat{a}_j * lb_j, & \mbox{or} \\
8581 * \tilde{a}_j * ub_j == -\hat{a}_j * ub_j &
8582 * \end{array}
8583 * \f]
8584 * to the rhs.
8585 *
8586 * (vlb or vub):
8587 * \f[
8588 * \begin{array}{lllll}
8589 * 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)} \\
8590 * 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)}
8591 * \end{array}
8592 * \f]
8593 * move the constant terms
8594 * \f[
8595 * \begin{array}{rl}
8596 * -\tilde{a}_j * dl_j == -\hat{a}_j * dl_j,& \mbox{or} \\
8597 * \tilde{a}_j * du_j == -\hat{a}_j * du_j &
8598 * \end{array}
8599 * \f]
8600 * to the rhs, and update the VB variable coefficients:
8601 * \f[
8602 * \begin{array}{ll}
8603 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j * bl_j == \hat{a}_{zl_j} - \hat{a}_j * bl_j,& \mbox{or} \\
8604 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j * bu_j == \hat{a}_{zu_j} - \hat{a}_j * bu_j &
8605 * \end{array}
8606 * \f]
8607 */
8608static
8610 SCIP* scip, /**< SCIP data structure */
8611 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8612 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8613 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8614 int* nnz, /**< number of non-zeros in cut */
8615 int* varsign, /**< stores the sign of the transformed variable in summation */
8616 int* boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub)*/
8617 QUAD(SCIP_Real f0), /**< fractional value of rhs */
8618 SCIP_Real k /**< factor to strengthen strongcg cut */
8619 )
8620{
8621 SCIP_Real QUAD(onedivoneminusf0);
8622 int i;
8623 int firstcontvar;
8624 SCIP_VAR** vars;
8625 int aggrrowintstart;
8626
8628 assert(cutcoefs != NULL);
8629 assert(cutinds != NULL);
8630 assert(nnz != NULL);
8631 assert(boundtype != NULL);
8632 assert(varsign != NULL);
8633 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
8634
8637
8638 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
8639 * without destroying the ordering of the aggrrow's non-zeros.
8640 * (due to sorting in cutsTransformStrongCG the ordering is continuous before integral)
8641 */
8642
8645#ifndef NDEBUG
8646 /* in debug mode check, that all continuous variables of the aggrrow come before the integral variables */
8647 i = 0;
8648 while( i < *nnz && cutinds[i] >= firstcontvar )
8649 {
8651 ++i;
8652 }
8653 while( i < *nnz )
8654 {
8657 ++i;
8658 }
8659#endif
8660
8661 /* integer variables */
8662 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
8663 {
8664 SCIP_VAR* var;
8665 SCIP_Real QUAD(aj);
8666 SCIP_Real QUAD(downaj);
8667 SCIP_Real QUAD(cutaj);
8668 SCIP_Real QUAD(fj);
8669 SCIP_Real QUAD(tmp);
8670 SCIP_Real bound;
8671 int v;
8672
8673 v = cutinds[i];
8674 assert(0 <= v && v < SCIPgetNVars(scip));
8675
8676 var = vars[v];
8677 assert(var != NULL);
8679 assert(boundtype[i] == -1 || boundtype[i] == -2);
8680 assert(varsign[i] == +1 || varsign[i] == -1);
8681
8682 /* calculate the coefficient in the retransformed cut */
8685
8686 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
8688
8689 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
8690 QUAD_ASSIGN_Q(cutaj, downaj); /* a_j */
8691 else
8692 {
8693 SCIP_Real pj;
8694
8695 SCIPquadprecSumQQ(cutaj, fj, -f0);
8699 assert(pj >= 0); /* should be >= 1, but due to rounding bias can be 0 if fj is almost equal to f0 */
8700 assert(pj <= k);
8701 SCIPquadprecDivDD(cutaj, pj, k + 1.0);
8703 }
8704
8706
8707 /* remove zero cut coefficients from cut */
8709 {
8710 QUAD_ASSIGN(cutaj, 0.0);
8712 --*nnz;
8713 cutinds[i] = cutinds[*nnz];
8714 continue;
8715 }
8716
8718
8719 /* integral var uses standard bound */
8720 assert(boundtype[i] < 0);
8721
8722 /* 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 */
8723 if( varsign[i] == +1 )
8724 {
8725 /* lower bound was used */
8726 if( boundtype[i] == -1 )
8728 else
8731 }
8732 else
8733 {
8734 /* upper bound was used */
8735 if( boundtype[i] == -1 )
8737 else
8740 }
8743 }
8744
8745 /* now process the continuous variables; postpone deletion of zeros until all continuous variables have been processed */
8746 aggrrowintstart = i + 1;
8747
8748#ifndef NDEBUG
8749 /* in a strong CG cut, cut coefficients of continuous variables are always zero; check this in debug mode */
8750 for( i = 0; i < aggrrowintstart; ++i )
8751 {
8752 SCIP_Real QUAD(aj);
8753 SCIP_VAR* var;
8754 int v;
8755
8756 v = cutinds[i];
8757 assert(firstcontvar <= v && v < SCIPgetNVars(scip));
8758
8759 var = vars[v];
8760 assert(var != NULL);
8763 assert(varsign[i] == +1 || varsign[i] == -1);
8764
8765 /* calculate the coefficient in the retransformed cut */
8768
8769 assert(QUAD_TO_DBL(aj) >= 0.0);
8770 }
8771#endif
8772
8773 /* set continuous variable coefficients to 0 */
8774 if( aggrrowintstart > 0 )
8775 {
8776 SCIP_Real QUAD(tmp);
8777 assert(aggrrowintstart <= *nnz);
8778
8779 /* explicitly set continuous variable coefficients to 0 */
8780 QUAD_ASSIGN(tmp, 0.0);
8781 for( i = 0; i < aggrrowintstart; ++i )
8782 {
8784 }
8785
8786 /* fill empty positions of the continuous variables by integral variables; copy all indices to the front or only
8787 * use the indices at the end, whatever is faster */
8788 *nnz -= aggrrowintstart;
8789 if( *nnz < aggrrowintstart )
8790 {
8792 }
8793 else
8794 {
8796 }
8797 }
8798
8799 return SCIP_OKAY;
8800}
8801
8802/** substitute aggregated slack variables:
8803 *
8804 * 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
8805 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r] \f$.
8806 *
8807 * Depending on the slack's type (integral or continuous), its coefficient in the cut calculates as follows:
8808 * \f[
8809 * \begin{array}{rll}
8810 * integers: & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & if \qquad f_r \leq f_0 \\
8811 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + p_r/(k + 1), & if \qquad f_r > f_0 \\
8812 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & if \qquad a^\prime_r \geq 0 \\
8813 * & \mbox{no strong CG cut found}, & if \qquad a^\prime_r < 0
8814 * \end{array}
8815 * \f]
8816 *
8817 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
8818 */
8819static
8821 SCIP* scip, /**< SCIP datastructure */
8822 SCIP_Real* weights, /**< row weights in row summation */
8823 int* slacksign, /**< stores the sign of the row's slack variable in summation */
8824 int* rowinds, /**< sparsity pattern of used rows */
8825 int nrowinds, /**< number of used rows */
8826 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
8827 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8828 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8829 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8830 int* nnz, /**< number of non-zeros in cut */
8831 QUAD(SCIP_Real f0), /**< fractional value of rhs */
8832 SCIP_Real k /**< factor to strengthen strongcg cut */
8833 )
8834{ /*lint --e{715}*/
8835 SCIP_ROW** rows;
8836 SCIP_Real QUAD(onedivoneminusf0);
8837 int i;
8838
8839 assert(scip != NULL);
8840 assert(weights != NULL);
8841 assert(slacksign != NULL);
8842 assert(rowinds != NULL);
8843 assert(SCIPisPositive(scip, scale));
8844 assert(cutcoefs != NULL);
8846 assert(cutinds != NULL);
8847 assert(nnz != NULL);
8848 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
8849
8852
8853 rows = SCIPgetLPRows(scip);
8854 for( i = 0; i < nrowinds; i++ )
8855 {
8856 SCIP_ROW* row;
8857 SCIP_Real pr;
8858 SCIP_Real QUAD(ar);
8859 SCIP_Real QUAD(downar);
8860 SCIP_Real QUAD(cutar);
8861 SCIP_Real QUAD(fr);
8862 SCIP_Real mul;
8863 int r;
8864
8865 r = rowinds[i];
8866 assert(0 <= r && r < SCIPgetNLPRows(scip));
8867 assert(slacksign[i] == -1 || slacksign[i] == +1);
8868 assert(!SCIPisZero(scip, weights[i]));
8869
8870 row = rows[r];
8871 assert(row != NULL);
8872 assert(row->len == 0 || row->cols != NULL);
8873 assert(row->len == 0 || row->cols_index != NULL);
8874 assert(row->len == 0 || row->vals != NULL);
8875
8876 /* get the slack's coefficient a'_r in the aggregated row */
8877 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
8878
8879 /* calculate slack variable's coefficient a_r in the cut */
8880 if( row->integral )
8881 {
8882 /* slack variable is always integral */
8883 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
8885
8886 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
8887 QUAD_ASSIGN_Q(cutar, downar); /* a_r */
8888 else
8889 {
8890 SCIPquadprecSumQQ(cutar, fr, -f0);
8894 assert(pr >= 0); /* should be >= 1, but due to rounding bias can be 0 if fr is almost equal to f0 */
8895 assert(pr <= k);
8896 SCIPquadprecDivDD(cutar, pr, k + 1.0);
8898 }
8899 }
8900 else
8901 {
8902 /* slack variable is continuous: */
8903 assert(QUAD_TO_DBL(ar) >= 0.0);
8904 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
8905 }
8906
8907 /* if the coefficient was reduced to zero, ignore the slack variable */
8909 continue;
8910
8911 /* depending on the slack's sign, we have
8912 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
8913 * substitute a_r * s_r by adding a_r times the slack's definition to the cut.
8914 */
8915 mul = -slacksign[i] * QUAD_TO_DBL(cutar);
8916
8917 /* add the slack's definition multiplied with a_j to the cut */
8919
8920 /* move slack's constant to the right hand side */
8921 if( slacksign[i] == +1 )
8922 {
8923 SCIP_Real rhs;
8924
8925 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a_r * (rhs - c) to the right hand side */
8926 assert(!SCIPisInfinity(scip, row->rhs));
8927 rhs = row->rhs - row->constant;
8928 if( row->integral )
8929 {
8930 /* the right hand side was implicitly rounded down in row aggregation */
8931 rhs = SCIPfloor(scip, rhs);
8932 }
8933
8936 }
8937 else
8938 {
8939 SCIP_Real lhs;
8940
8941 /* a*x + c - s == lhs => s == a*x + c - lhs: move a_r * (c - lhs) to the right hand side */
8942 assert(!SCIPisInfinity(scip, -row->lhs));
8943 lhs = row->lhs - row->constant;
8944 if( row->integral )
8945 {
8946 /* the left hand side was implicitly rounded up in row aggregation */
8947 lhs = SCIPceil(scip, lhs);
8948 }
8949
8952 }
8953 }
8954
8955 /* relax rhs to zero, if it's very close to 0 */
8956 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
8957 QUAD_ASSIGN(*cutrhs, 0.0);
8958
8959 return SCIP_OKAY;
8960}
8961
8962
8963/** calculates a strong CG cut out of the weighted sum of LP rows given by an aggregation row; the
8964 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
8965 * participate in a strongcg cut
8966 *
8967 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8968 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8969 *
8970 * @pre This method can be called if @p scip is in one of the following stages:
8971 * - \ref SCIP_STAGE_SOLVING
8972 *
8973 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
8974 */
8976 SCIP* scip, /**< SCIP data structure */
8977 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8978 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
8979 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
8980 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
8981 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8982 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce strong CG cut for */
8983 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce strong CG cut for */
8984 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
8985 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute a strong CG cut for */
8986 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
8987 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
8988 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
8989 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
8990 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
8991 int* cutrank, /**< pointer to return rank of generated cut */
8992 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
8993 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
8994 )
8995{
8996 int i;
8997 int nvars;
8998 int* varsign;
8999 int* boundtype;
9000 SCIP_Real* tmpcoefs;
9001 SCIP_Real QUAD(downrhs);
9002 SCIP_Real QUAD(f0);
9003 SCIP_Real QUAD(tmp);
9004 SCIP_Real QUAD(rhs);
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);
9017
9018 SCIPdebugMsg(scip, "calculating strong CG cut (scale: %g)\n", scale);
9019
9020 *success = FALSE;
9021
9022 /* check whether a negative continuous slack variable in a non-integral row is present in the aggregation, since then
9023 * no strongcg cut can be generated */
9024 for( i = 0; i < aggrrow->nrows; ++i )
9025 {
9026 if( aggrrow->rowweights[i] * aggrrow->slacksign[i] < 0.0 && !scip->lp->rows[aggrrow->rowsinds[i]]->integral )
9027 return SCIP_OKAY;
9028 }
9029
9030 /* allocate temporary memory */
9033 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
9035
9036 /* initialize cut with aggregation */
9037 *cutnnz = aggrrow->nnz;
9038 *cutislocal = aggrrow->local;
9039 SCIPquadprecProdQD(rhs, aggrrow->rhs, scale);
9040
9041 if( *cutnnz > 0 )
9042 {
9044
9045 for( i = 0; i < *cutnnz; ++i )
9046 {
9047 SCIP_Real QUAD(coef);
9048 int j = cutinds[i];
9049
9050 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
9051 SCIPquadprecProdQD(coef, coef, scale);
9052
9053 QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
9054 assert(QUAD_HI(coef) != 0.0);
9055
9056 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
9057 }
9058
9059 /* Transform equation a*x == b, lb <= x <= ub into standard form
9060 * a'*x' == b, 0 <= x' <= ub'.
9061 *
9062 * Transform variables (lb or ub):
9063 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
9064 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
9065 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
9066 *
9067 * Transform variables (vlb or vub):
9068 * 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.
9069 * 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.
9070 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
9071 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
9072 * a_{zu_j} := a_{zu_j} + a_j * bu_j
9073 */
9075 tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, &freevariable, &localbdsused) );
9076
9077 assert(allowlocal || !localbdsused);
9079
9080 if( freevariable )
9081 goto TERMINATE;
9082
9084 }
9085
9086 /* Calculate
9087 * - fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j)
9088 * - integer k >= 1 with 1/(k + 1) <= f_0 < 1/k
9089 * (=> k = up(1/f_0) - 1)
9090 * - 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)
9091 * (=> p_j = up( (f_j - f_0)/((1 - f_0)/k) ))
9092 * and derive strong CG cut
9093 * a~*x' <= (k+1) * down(b)
9094 * integers : a~_j = down(a'_j) , if f_j <= f_0
9095 * a~_j = down(a'_j) + p_j/(k + 1) , if f_j > f_0
9096 * continuous: a~_j = 0 , if a'_j >= 0
9097 * no strong CG cut found , if a'_j < 0
9098 *
9099 * Transform inequality back to a^*x <= rhs:
9100 *
9101 * (lb or ub):
9102 * 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
9103 * 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
9104 * and move the constant terms
9105 * -a~_j * lb_j == -a^_j * lb_j, or
9106 * a~_j * ub_j == -a^_j * ub_j
9107 * to the rhs.
9108 *
9109 * (vlb or vub):
9110 * 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)
9111 * 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)
9112 * move the constant terms
9113 * -a~_j * dl_j == -a^_j * dl_j, or
9114 * a~_j * du_j == -a^_j * du_j
9115 * to the rhs, and update the VB variable coefficients:
9116 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
9117 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
9118 */
9119 SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
9120
9121 SCIPquadprecSumQQ(f0, rhs, -downrhs);
9122 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
9123 goto TERMINATE;
9124
9125 /* renormalize the f0 value */
9126 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
9127
9128 SCIPquadprecDivDQ(tmp, 1.0, f0);
9129 SCIPquadprecSumQD(tmp, tmp, -1.0);
9131
9132 QUAD_ASSIGN_Q(rhs, downrhs);
9133
9134 if( *cutnnz > 0 )
9135 {
9136 SCIP_CALL( cutsRoundStrongCG(scip, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, QUAD(f0), k) );
9138 }
9139
9140 /* substitute aggregated slack variables:
9141 *
9142 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
9143 * variable only appears in its own row:
9144 * a'_r = scale * weight[r] * slacksign[r].
9145 *
9146 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
9147 * integers : a_r = a~_r = (k + 1) * down(a'_r) , if f_r <= f0
9148 * a_r = a~_r = (k + 1) * down(a'_r) + p_r , if f_r > f0
9149 * continuous: a_r = a~_r = 0 , if a'_r >= 0
9150 * a_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
9151 *
9152 * Substitute a_r * s_r by adding a_r times the slack's definition to the cut.
9153 */
9154 SCIP_CALL( cutsSubstituteStrongCG(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
9155 aggrrow->nrows, scale, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, QUAD(f0), k) );
9157
9158 /* remove all nearly-zero coefficients from strong CG row and relax the right hand side correspondingly in order to
9159 * prevent numerical rounding errors
9160 */
9161 if( postprocess )
9162 {
9164 }
9165 else
9166 {
9168 }
9170
9171 if( *success )
9172 {
9173 *cutrhs = QUAD_TO_DBL(rhs);
9174
9175 /* store cut in given array in sparse representation and clean buffer array */
9176 for( i = 0; i < *cutnnz; ++i )
9177 {
9178 SCIP_Real QUAD(coef);
9179 int j = cutinds[i];
9180
9181 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
9182 assert(QUAD_HI(coef) != 0.0);
9183
9184 cutcoefs[i] = QUAD_TO_DBL(coef);
9185 QUAD_ASSIGN(coef, 0.0);
9186 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
9187 }
9188
9189 if( cutefficacy != NULL )
9191
9192 if( cutrank != NULL )
9193 *cutrank = aggrrow->rank + 1;
9194 }
9195
9196 TERMINATE:
9197
9198 /* if we aborted early the tmpcoefs array needs to be cleaned */
9199 if( !(*success) )
9200 {
9201 QUAD_ASSIGN(tmp, 0.0);
9202
9203 for( i = 0; i < *cutnnz; ++i )
9204 {
9206 }
9207 }
9208
9209 /* free temporary memory */
9211 SCIPfreeBufferArray(scip, &boundtype);
9213
9214 return SCIP_OKAY;
9215}
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:4136
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:7842
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:7552
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:8820
static SCIP_RETCODE computeLiftingData(SCIP *scip, SNF_RELAXATION *snf, int *transvarflowcoverstatus, SCIP_Real lambda, LIFTINGDATA *liftingdata, SCIP_Bool *valid)
Definition cuts.c:7004
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:4967
static SCIP_RETCODE getFlowCover(SCIP *scip, SNF_RELAXATION *snf, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, SCIP_Real *lambda, SCIP_Bool *found)
Definition cuts.c:6616
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:5097
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:8385
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:7958
#define MAXBOUND
Definition cuts.c:4919
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:5406
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:7134
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:6005
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:5225
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:5985
static SCIP_RETCODE allocSNFRelaxation(SCIP *scip, SNF_RELAXATION *snf, int nvars)
Definition cuts.c:5964
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:8609
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:6100
#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:7147
static void getAlphaAndBeta(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real vubcoef, int *alpha, SCIP_Real *beta)
Definition cuts.c:6967
#define MAXABSVBCOEF
Definition cuts.c:4918
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:7751
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:6883
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 EPSFLOOR(x, eps)
Definition def.h:206
#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:4218
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:8975
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:8058
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:7428
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:3879
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_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:6634
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:6611
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:4926
SCIP_Real lambda
Definition cuts.c:4937
SCIP_Real * m
Definition cuts.c:4927
SCIP_Real d2
Definition cuts.c:4936
SCIP_Real mp
Definition cuts.c:4938
SCIP_Real ml
Definition cuts.c:4939
SCIP_Real d1
Definition cuts.c:4935
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:4947
int * transvarcoefs
Definition cuts.c:4946
SCIP_Real * transcontvarsolvals
Definition cuts.c:4948
SCIP_Real * aggrcoefsbin
Definition cuts.c:4954
int * origcontvars
Definition cuts.c:4953
SCIP_Real transrhs
Definition cuts.c:4951
int * origbinvars
Definition cuts.c:4952
SCIP_Real * aggrconstants
Definition cuts.c:4958
SCIP_Real * aggrcoefscont
Definition cuts.c:4956
int ntransvars
Definition cuts.c:4950
SCIP_Real * transvarvubcoefs
Definition cuts.c:4949
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