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