Scippy

SCIP

Solving Constraint Integer Programs

cuts.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-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
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
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
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
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
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
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 
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 
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
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
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
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
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
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  */
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 */
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 */
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 */
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 */
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 */
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  */
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 */
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 */
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 */
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  */
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
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  {
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  */
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
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
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. */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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
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
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
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
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
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
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
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  */
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 
3838  SCIPdebugMessage("calculating MIR cut (scale: %g)\n", scale);
3839 
3840  *success = FALSE;
3841 
3842  /* allocate temporary memory */
3843  nvars = SCIPgetNVars(scip);
3844  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
3845  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
3846  SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
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 
3855  if( tmpnnz > 0 )
3856  {
3857  BMScopyMemoryArray(tmpinds, aggrrow->inds, tmpnnz);
3858 
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);
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  */
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);
3891  tmpislocal = tmpislocal || localbdsused;
3892 
3893  if( freevariable )
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  */
3925  SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
3926 
3927  SCIPquadprecSumQQ(f0, rhs, -downrhs);
3928 
3929  if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
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  */
3935  if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
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 
3943  if( tmpnnz > 0 )
3944  {
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  */
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 
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
3975  {
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
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  */
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
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
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
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 
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 
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
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,
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
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
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);
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
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
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
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
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
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
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
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
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
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
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  */
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
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
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
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
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  */
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
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
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
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  */
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 }
void SCIPsortDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, int len)
SCIP_Real * transbinvarsolvals
Definition: cuts.c:4851
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:101
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:596
static SCIP_RETCODE postprocessCutQuad(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, QUAD(SCIP_Real *cutrhs), SCIP_Bool *success)
Definition: cuts.c:2331
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:90
SCIP_RETCODE SCIPcalcStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:8866
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1686
static SCIP_RETCODE computeLiftingData(SCIP *scip, SNF_RELAXATION *snf, int *transvarflowcoverstatus, SCIP_Real lambda, LIFTINGDATA *liftingdata, SCIP_Bool *valid)
Definition: cuts.c:6905
int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2405
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18124
SCIP_Real lambda
Definition: cuts.c:4841
SCIP_Real SCIPfeastol(SCIP *scip)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_Real d1
Definition: cuts.c:4839
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int ntransvars
Definition: cuts.c:4854
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int * origcontvars
Definition: cuts.c:4857
SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
Definition: cuts.c:1790
#define SCIPquadprecDivDQ(r, a, b)
Definition: dbldblarith.h:55
#define SCIPquadprecSumQD(r, a, b)
Definition: dbldblarith.h:53
static SCIP_RETCODE varVecAddScaledRowCoefsQuad(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:160
int * cols_index
Definition: struct_lp.h:219
SCIP_Real * aggrcoefscont
Definition: cuts.c:4860
public methods for memory management
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18102
enum SCIP_BaseStat SCIP_BASESTAT
Definition: type_lpi.h:87
static SCIP_RETCODE cutTightenCoefsQuad(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
Definition: cuts.c:722
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17910
static void performBoundSubstitution(SCIP *scip, int *cutinds, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *nnz, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition: cuts.c:2836
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
static long bound
void SCIPaggrRowCancelVarWithBound(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_VAR *var, int pos, SCIP_Bool *valid)
Definition: cuts.c:1874
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17966
#define QUAD_ARRAY_STORE(a, idx, x)
Definition: dbldblarith.h:46
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real transrhs
Definition: cuts.c:4855
static SCIP_RETCODE SCIPsolveKnapsackApproximatelyLT(SCIP *scip, int nitems, SCIP_Real *weights, SCIP_Real *profits, SCIP_Real capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
Definition: cuts.c:5909
int rank
Definition: struct_lp.h:239
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17431
#define MAXABSVBCOEF
Definition: cuts.c:4822
static SCIP_Real computeMIREfficacy(SCIP *scip, SCIP_Real *RESTRICT coefs, SCIP_Real *RESTRICT solvals, SCIP_Real rhs, SCIP_Real contactivity, SCIP_Real contsqrnorm, SCIP_Real delta, int nvars, SCIP_Real minfrac, SCIP_Real maxfrac)
Definition: cuts.c:4042
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPquadprecProdQQ(r, a, b)
Definition: dbldblarith.h:57
SCIP_Real * M
Definition: cuts.c:4830
static SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
Definition: cuts.c:585
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1865
static SCIP_RETCODE generateLiftedFlowCoverCut(SCIP *scip, SNF_RELAXATION *snf, SCIP_AGGRROW *aggrrow, int *flowcoverstatus, SCIP_Real lambda, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *nnz, SCIP_Bool *success)
Definition: cuts.c:7048
struct LiftingData LIFTINGDATA
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17225
#define FALSE
Definition: def.h:87
#define EPSISINT(x, eps)
Definition: def.h:214
methods for the aggregation rows
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11063
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition: lp.c:17273
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:86
#define SCIPdebug(x)
Definition: pub_message.h:84
SCIP_Bool SCIPaggrRowIsLocal(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2490
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static SCIP_RETCODE cutsTransformStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition: cuts.c:8276
SCIP_RETCODE SCIPcutGenerationHeuristicCMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, int maxtestdelta, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:4124
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18144
#define MAXCMIRSCALE
Definition: cuts.c:2511
static SCIP_RETCODE cutsSubstituteMIR(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, QUAD(SCIP_Real f0))
Definition: cuts.c:3638
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17600
#define SCIP_UNUSED(x)
Definition: def.h:438
static SCIP_Real evaluateLiftingFunction(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real x)
Definition: cuts.c:6784
public methods for problem variables
static SCIP_RETCODE findBestUb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, SCIP_Real *simplebound, int *bestubtype)
Definition: cuts.c:2576
SCIP_RETCODE SCIPcalcKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:7955
int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2470
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:99
SCIP_Real SCIPaggrRowGetRhs(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2500
#define QUAD_SCALE(x, a)
Definition: dbldblarith.h:41
#define SCIPdebugMessage
Definition: pub_message.h:87
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18114
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:79
unsigned int integral
Definition: struct_lp.h:248
#define EPSFRAC(x, eps)
Definition: def.h:213
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPaggrRowPrint(SCIP *scip, SCIP_AGGRROW *aggrrow, FILE *file)
Definition: cuts.c:1707
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int * slacksign
Definition: struct_cuts.h:36
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
#define QUAD_ASSIGN(a, constant)
Definition: dbldblarith.h:42
defines macros for basic operations in double-double arithmetic giving roughly twice the precision of...
public methods for SCIP variables
int * rowsinds
Definition: struct_cuts.h:35
#define SCIPdebugMsgPrint
Definition: scip_message.h:70
#define SCIPdebugMsg
Definition: scip_message.h:69
static void prepareLiftingData(SCIP *scip, SCIP_Real *cutcoefs, int *cutinds, QUAD(SCIP_Real cutrhs), int *coverpos, int coversize, QUAD(SCIP_Real coverweight), SCIP_Real *covervals, int *coverstatus, QUAD(SCIP_Real *abar), int *cplussize)
Definition: cuts.c:7743
internal methods for LP management
SCIP_VAR ** x
Definition: circlepacking.c:54
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2171
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_RETCODE SCIPgetVarClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: scip_var.c:6606
#define QUAD_TO_DBL(x)
Definition: dbldblarith.h:40
SCIP_Real SCIPgetRowMaxActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1941
static void getAlphaAndBeta(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real vubcoef, int *alpha, SCIP_Real *beta)
Definition: cuts.c:6868
public methods for numerical tolerances
SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
Definition: cuts.c:2437
static void destroyLiftingData(SCIP *scip, LIFTINGDATA *liftingdata)
Definition: cuts.c:7035
public methods for querying solving statistics
SCIP_RETCODE SCIPaggrRowAddObjectiveFunction(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real rhs, SCIP_Real scale)
Definition: cuts.c:1933
static SCIP_Real calcEfficacyNormQuad(SCIP *scip, SCIP_Real *vals, int *inds, int nnz)
Definition: cuts.c:266
static SCIP_RETCODE cutTightenCoefs(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
Definition: cuts.c:1101
SCIP_Real * vals
Definition: struct_lp.h:220
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip_mem.h:133
SCIP_Real * rowweights
Definition: struct_cuts.h:37
static SCIP_Bool removeZerosQuad(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
Definition: cuts.c:403
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17920
int lppos
Definition: struct_lp.h:230
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:96
void SCIPsortDownInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
static SCIP_RETCODE varVecAddScaledRowCoefs(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:115
#define QUAD_HI(x)
Definition: dbldblarith.h:36
int * transvarcoefs
Definition: cuts.c:4850
SCIP_Bool SCIPsortedvecFindDownReal(SCIP_Real *realarray, SCIP_Real val, int len, int *pos)
int t
Definition: cuts.c:4838
int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2415
static SCIP_Bool isIntegralScalar(SCIP_Real val, SCIP_Real scalar, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Real *intval)
Definition: lp.c:4894
#define SCIPerrorMessage
Definition: pub_message.h:55
#define SCIPdebugPrintf
Definition: pub_message.h:90
#define QUAD_EPSILON
Definition: dbldblarith.h:33
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_COL ** cols
Definition: struct_lp.h:218
#define SCIPquadprecEpsFloorQ(r, a, eps)
Definition: dbldblarith.h:66
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17334
#define BMSmoveMemoryArray(ptr, source, num)
Definition: memory.h:131
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:128
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:126
#define QUAD(x)
Definition: dbldblarith.h:38
SCIP_Real lhs
Definition: struct_lp.h:195
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18176
SCIP_Real sepa_maxcoefratio
Definition: struct_set.h:530
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17251
static SCIP_Bool chgCoeffWithBound(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
Definition: cuts.c:630
int SCIPaggrRowGetRank(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2480
static SCIP_RETCODE cutsTransformMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition: cuts.c:2971
#define NULL
Definition: lpi_spx1.cpp:155
int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2460
#define REALABS(x)
Definition: def.h:201
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:18284
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:617
#define QUAD_ARRAY_LOAD(r, a, idx)
Definition: dbldblarith.h:45
void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool useglbbounds, SCIP_Bool *valid)
Definition: cuts.c:2390
#define SCIP_CALL(x)
Definition: def.h:384
static SCIP_Real evaluateLiftingFunctionKnapsack(QUAD(SCIP_Real x), QUAD(SCIP_Real abar), SCIP_Real *covervals, int coversize, int cplussize, SCIP_Real *scale)
Definition: cuts.c:7859
SCIP main data structure.
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18134
SCIP_VAR * h
Definition: circlepacking.c:59
SCIP_RETCODE SCIPgetVarClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvub, int *closestvubidx)
Definition: scip_var.c:6629
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17235
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18166
SCIP_RETCODE SCIPaggrRowAddCustomCons(SCIP *scip, SCIP_AGGRROW *aggrrow, int *inds, SCIP_Real *vals, int len, SCIP_Real rhs, SCIP_Real weight, int rank, SCIP_Bool local)
Definition: cuts.c:2004
#define MINDELTA
static SCIP_RETCODE getClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestsub, SCIP_Real rowcoef, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: cuts.c:4871
#define SCIPquadprecProdDD(r, a, b)
Definition: dbldblarith.h:49
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:17344
#define MAXBOUND
Definition: cuts.c:4823
static SCIP_Bool chgQuadCoeffWithBound(SCIP *scip, SCIP_VAR *var, QUAD(SCIP_Real oldcoeff), SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
Definition: cuts.c:675
static SCIP_RETCODE allocSNFRelaxation(SCIP *scip, SNF_RELAXATION *snf, int nvars)
Definition: cuts.c:5868
int var_probindex
Definition: struct_lp.h:169
SCIP_Real * aggrcoefsbin
Definition: cuts.c:4858
SCIP_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:3792
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
public data structures and miscellaneous methods
#define SCIP_Bool
Definition: def.h:84
static SCIP_RETCODE cutsSubstituteStrongCG(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, QUAD(SCIP_Real f0), SCIP_Real k)
Definition: cuts.c:8711
SCIP_Real SCIPaggrRowCalcEfficacyNorm(SCIP *scip, SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2079
#define QUAD_LO(x)
Definition: dbldblarith.h:37
#define QUAD_ARRAY_SIZE(size)
Definition: dbldblarith.h:44
SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
Definition: cuts.c:1462
SCIP_Bool SCIPisSumLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPcalcFlowCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:7329
#define MAX(x, y)
Definition: tclique_def.h:83
static SCIP_RETCODE determineBoundForSNF(SCIP *scip, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *rowcoefs, int *rowinds, int varposinrow, int8_t *binvarused, SCIP_Bool allowlocal, SCIP_Real boundswitch, SCIP_Real *bestlb, SCIP_Real *bestub, SCIP_Real *bestslb, SCIP_Real *bestsub, int *bestlbtype, int *bestubtype, int *bestslbtype, int *bestsubtype, SCIP_BOUNDTYPE *selectedbounds, SCIP_Bool *freevariable)
Definition: cuts.c:5129
public methods for LP management
public methods for cuts and aggregation rows
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17758
static SCIP_RETCODE constructSNFRelaxation(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_Real *rowcoefs, QUAD(SCIP_Real rowrhs), int *rowinds, int nnz, SNF_RELAXATION *snf, SCIP_Bool *success, SCIP_Bool *localbdsused)
Definition: cuts.c:5310
int * origbinvars
Definition: cuts.c:4856
#define SCIPquadprecProdQD(r, a, b)
Definition: dbldblarith.h:54
SCIP_Real * SCIPaggrRowGetRowWeights(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2426
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:127
static SCIP_RETCODE cutsRoundStrongCG(SCIP *scip, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, QUAD(SCIP_Real f0), SCIP_Real k)
Definition: cuts.c:8500
static SCIP_RETCODE addOneRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *rowtoolong)
Definition: cuts.c:2091
#define MAXDNOM
Definition: cons_linear.c:176
static SCIP_RETCODE getClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestslb, SCIP_Real rowcoef, SCIP_Real *closestvub, int *closestvubidx)
Definition: cuts.c:5001
char sepa_efficacynorm
Definition: struct_set.h:539
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2129
SCIP_Real * transvarvubcoefs
Definition: cuts.c:4853
SCIP_Real * vals
Definition: struct_cuts.h:33
struct SNF_Relaxation SNF_RELAXATION
SCIP_ROW ** rows
Definition: struct_lp.h:293
#define SCIPquadprecSumQQ(r, a, b)
Definition: dbldblarith.h:58
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2036
public methods for the LP relaxation, rows and columns
#define QUAD_ASSIGN_Q(a, b)
Definition: dbldblarith.h:43
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1991
#define SCIP_REAL_MAX
Definition: def.h:178
SCIP_Real rhs
Definition: struct_lp.h:196
SCIP_Real constant
Definition: struct_lp.h:194
#define MAXSCALE
SCIP_Real * r
Definition: circlepacking.c:50
methods for sorting joint arrays of various types
static SCIP_RETCODE cutsRoundMIR(SCIP *scip, SCIP_Real *RESTRICT cutcoefs, QUAD(SCIP_Real *RESTRICT cutrhs), int *RESTRICT cutinds, int *RESTRICT nnz, int *RESTRICT varsign, int *RESTRICT boundtype, QUAD(SCIP_Real f0))
Definition: cuts.c:3327
SCIP_RETCODE SCIPaggrRowCopy(SCIP *scip, SCIP_AGGRROW **aggrrow, SCIP_AGGRROW *source)
Definition: cuts.c:1744
#define SCIPquadprecDivDD(r, a, b)
Definition: dbldblarith.h:52
int r
Definition: cuts.c:4837
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE determineBestBounds(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real boundswitch, int usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real *bestlb, SCIP_Real *bestub, int *bestlbtype, int *bestubtype, SCIP_BOUNDTYPE *selectedbound, SCIP_Bool *freevariable)
Definition: cuts.c:2637
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPaggrRowSumRows(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real *weights, int *rowinds, int nrowinds, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *valid)
Definition: cuts.c:2198
void SCIPselectWeightedDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
public methods for solutions
static SCIP_Bool removeZeros(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
Definition: cuts.c:496
static void destroySNFRelaxation(SCIP *scip, SNF_RELAXATION *snf)
Definition: cuts.c:5889
SCIP_SET * set
Definition: struct_scip.h:63
int SCIPgetNCuts(SCIP *scip)
Definition: scip_cut.c:778
static void buildFlowCover(SCIP *scip, int *coefs, SCIP_Real *vubcoefs, SCIP_Real rhs, int *solitems, int *nonsolitems, int nsolitems, int nnonsolitems, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, QUAD(SCIP_Real *flowcoverweight), SCIP_Real *lambda)
Definition: cuts.c:6004
public methods for message output
data structures for LP management
SCIP_Real * aggrconstants
Definition: cuts.c:4862
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:609
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1946
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17434
void SCIPsortDownInt(int *intarray, int len)
static SCIP_RETCODE postprocessCut(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, SCIP_Real *cutrhs, SCIP_Bool *success)
Definition: cuts.c:2262
#define SCIP_Real
Definition: def.h:177
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip_mem.h:137
SCIP_Real SCIPgetRowMinActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1924
public methods for message handling
static SCIP_RETCODE findBestLb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, SCIP_Real *simplebound, int *bestlbtype)
Definition: cuts.c:2515
#define SCIP_INVALID
Definition: def.h:197
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1654
#define SCIPquadprecSumDD(r, a, b)
Definition: dbldblarith.h:51
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18156
#define SCIP_Longint
Definition: def.h:162
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition: misc.c:9458
SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17416
#define NONZERO(x)
Definition: cuts.c:109
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real d2
Definition: cuts.c:4840
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17976
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:102
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPsumepsilon(SCIP *scip)
SCIP_Real ml
Definition: cuts.c:4843
#define EPSFLOOR(x, eps)
Definition: def.h:210
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:123
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:561
static SCIP_RETCODE getFlowCover(SCIP *scip, SNF_RELAXATION *snf, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, SCIP_Real *lambda, SCIP_Bool *found)
Definition: cuts.c:6520
SCIPallocBlockMemory(scip, subsol))
static SCIP_RETCODE cutsTransformKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *localbdsused, SCIP_Bool *success)
Definition: cuts.c:7453
void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2054
static SCIP_Bool computeInitialKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, int *cutinds, SCIP_Real cutrhs, int cutnnz, int *varsign, int *coverstatus, int *coverpos, SCIP_Real *covervals, int *coversize, QUAD(SCIP_Real *coverweight))
Definition: cuts.c:7652
#define SCIP_CALL_ABORT(x)
Definition: def.h:363
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_LP * lp
Definition: struct_scip.h:82
SCIP_Longint SCIPgetNLPs(SCIP *scip)
#define SCIPABORT()
Definition: def.h:356
SCIP_Real * m
Definition: cuts.c:4831
public methods for global and local (sub)problems
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17442
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352
datastructures for global SCIP settings
static SCIP_Real calcEfficacyDenseStorageQuad(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:328
static void performBoundSubstitutionSimple(SCIP *scip, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition: cuts.c:2916
void SCIPsortDownReal(SCIP_Real *realarray, int len)
SCIP_Real * transcontvarsolvals
Definition: cuts.c:4852
#define MAXDELTA
unsigned int local
Definition: struct_lp.h:249
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
#define EPSZ(x, eps)
Definition: def.h:207
SCIP_Real mp
Definition: cuts.c:4842
int len
Definition: struct_lp.h:226
static SCIP_Real calcEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:201
SCIP_Bool local
Definition: struct_cuts.h:43
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17580
methods for selecting (weighted) k-medians
memory allocation routines